home *** CD-ROM | disk | FTP | other *** search
Wrap
Text File | 1999-05-04 | 143.9 KB | 5,319 lines | [ TEXT/CWIE]
/* File: SimpleText.c Contains: SimpleText - a simple document editing application for shipping with system software. Version: SimpleText 1.4 or later Written by: TED = Tom Dowdy DAL = Dave Lyons Copyright: © 1993-1998 by Apple Computer, Inc., all rights reserved. File Ownership: DRI: Tom Dowdy Other Contact: Jim Negrette Technology: Macintosh Graphics Group Writers: (dmp) Dave Polaschek (ecs) Eric Schlegel (ted) Tom Dowdy (Gr) Greg Robbins (TD) Tom Dowdy Change History (most recent first): $Log: SimpleText.c,v $ Revision 1.37 1999/04/15 23:27:36 ericsc Fix starting item index in AreAllMenuItemsEnabled; remove EnsureAppleMenu. Revision 1.36 1999/04/12 19:04:36 poon Carbonized printing loop Revision 1.35 1999/04/08 21:47:02 voas Change to always call InitCursor. This seems to cause the drag manager to get initialized. No, I'm not kidding. Revision 1.34 1999/04/01 22:53:26 devans Add code to Compile and Execute selections as AppleScripts. Revision 1.33 1999/03/03 23:14:29 guyf Use new control creation APIs instead of NewControl Revision 1.32 1999/02/19 22:10:59 danp Changes to support opaque regions. Revision 1.31 1999/02/16 01:02:33 christ Use GetQDGlobalsScreenBits, not qd.screenBits, when calling DragWindow Revision 1.30 1999/02/16 00:41:39 christ Integrate document proxy icon support Revision 1.29 1999/02/10 01:01:01 danp Adding Andy Carroll's changes so we compile correctly on both X and MacOS 8.5 Revision 1.28 1999/02/05 18:58:25 ericsc Use Enable/DisableAllMenuItems. Revision 1.27 1999/01/26 23:40:19 wilkes Update for opaque AEDesc's. Revision 1.26 1999/01/08 04:42:00 christ Text dragging support is back. Revision 1.25 1998/12/03 00:05:48 kilroy Removed Balloons and AppleGuide Revision 1.24 1998/11/25 21:01:20 wilkes Removed all GX references. Revision 1.23 1998/11/19 01:16:19 wilkes Removed reliance on QuickTime. Most changes were conditionalized with ALLOW_QUICKTIME... Revision 1.22 1998/11/11 22:28:56 wilkes Fixed various problems caused by the interface changes made by Nitin earlier, mostly involving static RoutineDescriptors... Revision 1.21 1998/10/19 23:53:46 voas Make work with latest HLTB. Revision 1.20 1998/10/14 18:52:47 voas Eliminate all warnings. Get working with top of tree. Revision 1.19 1998/10/12 18:59:00 danp Modifications to allow cross-compiling and for CarbonLib support. Removed lots of GX stuff Revision 1.18 1998/10/01 23:00:37 marke in DoGrowWindow, add call to GetWindowPortBounds to update pData->contentRect. Nothing works unless content rect is updated after a resize, so this must've been an introduced bug Revision 1.17 1998/09/29 23:22:24 kilroy Fixed some stuff that I thought we already fixed. Like using InvalWindowRect. Revision 1.16 1998/09/15 22:54:15 voas Changed to reflect latest Carbon header changes I just made. Revision 1.15 1998/09/15 18:59:48 jiarocci SimpleText now builds with -DTARGET_CARBON=1. Still needs further cleanup. Revision 1.14 1998/09/15 00:19:25 mkellner Make Navigation support Revision 1.13 1998/09/12 23:09:09 voas Convince it to work without passing in storage for windows. Revision 1.12 1998/09/02 20:44:07 danp Minor changes for blue mwerks compiles Revision 1.11 1998/08/31 05:12:32 danp Removed AEGetAttributeDesc workaround. Revision 1.10 1998/08/27 23:21:07 danp Added new #includes for SimpleText.r because of new interfaces layout Placed stub for AEGetAttributeDesc due to undefined symbol in Carbon. Will need to remove once devans fixes that symbol. Revision 1.9 1998/08/24 20:58:56 voas Fix bug getting structure bounds. We were hanging onto a pointer to rgn bounds inside a deleted region. Revision 1.8 1998/05/10 07:28:35 devans Hack for TextEdit font size bug. Set and change the font size when we first fill in a TextEdit handle. This causes the right calcs to occur. Also return NULL from OpenDoc instead of whatever was on the stack. Revision 1.7 1998/05/06 22:21:25 devans Replace usage of qd.arrow with GetQDarrow(). Revision 1.6 1998/04/21 02:13:22 mkellner Add SimpleText app wrapper Revision 1.5 1998/03/30 22:12:29 mkellner Update to use new GetQDxxxx macros for qd.globals Revision 1.4 1998/03/21 04:13:15 mkellner Add a define for qd_screenBits for qd.screenBits. Replaced qd.screenBits with qd_screenBits Revision 1.3 1998/03/20 03:20:03 mkellner change qd.thePort to FrontWindow() add SysEnvirons Revision 1.2 1998/03/19 03:55:40 mkellner - Add <ConditionalMacros.h> and <QTMLMapNames.h> - Fix captialization of math.h, stdio.h, strings.h, etc. - Change Types.h, Memory.h and Windows.h to MacTypes, MacMemory, and MacWindows - Add inital set of stubs. - Change Types.r to MacTypes.r Revision 1.1.1.1 1998/03/18 22:56:11 ivory Initial checkin of SimpleText. 16 2/23/98 3:22 PM Tom Dowdy Test for negative width rectangles to avoid sometimes creating a new staggered window that wasn't actually there. 15 9/30/97 6:29 PM Sam Bushell Now tests unrecognised file types to see if there are graphics importers for them, and uses PICTFile if there are. 14 9/26/97 2:34 PM Tom Dowdy Fixed extended picture size rectangle 13 9/2/97 9:02 AM Tom Dowdy NIL finds are now just treated as cancels. 12 8/20/97 4:24 PM Tom Dowdy 1674136: adjust cursor after select all 11 8/18/97 12:18 PM Duane Byram don't need to increment kControlScrollBarLiveProc because of Appearance.h change 10 8/12/97 4:04 PM Tom Dowdy new staggering 9 8/11/97 3:36 PM Tom Dowdy Nav services now working! 8 8/11/97 3:01 PM Tom Dowdy rolling in nav services 7 7/30/97 4:05 PM Tom Dowdy Adjust cursor before mouse down 6 7/30/97 3:42 PM Tom Dowdy Live scrolling now 5 7/29/97 6:27 PM Tom Dowdy Added appearance 4 7/29/97 6:02 PM Tom Dowdy 'rapp' event support 3 7/29/97 2:06 PM Tom Dowdy Removed all of the old and boring refs 2 7/29/97 1:52 PM Tom Dowdy Various new interface fixes 1 7/28/97 11:20 AM Duane Byram first added to Source Safe project <49> 6/30/97 ted [1657956] Incorrect drag bounds <48> 5/14/97 ted More drag clipping bug fixes <47> 4/28/97 ted [1650434] Crash w/ QuickTime -- also fix incompat w/ AppleGuide <46> 1/13/97 ted fixing jump table offset link problems <45> 1/2/97 ecs call preMenuAccessProc before tracking menus <44> 1/2/97 ecs invalidate cursor region when windows are opened & closed; unhilite menu before adjust menus in DoCloseWindow to avoid ugly menu hilite flashing; InitCursor before menu tracking to make sure we've got an arrow cursor <43> 12/20/96 ted [1614876] 'rapp' event <42> 12/19/96 ted [1395082] Remove profiler <41> 12/6/96 ecs boot speed improvements: custom GetNewMBar, delayed Apple menu construction, don't redraw menu bar if AdjustMenus already did, cache menu handles in AdjustMenus <40> 12/5/96 ted Removing quit after print. Don't need to do that. <39> 12/5/96 ted [1609760] Adding drag flavor for clipping title <38> 12/3/96 ted [1608948] Fixing find for half script stuff. <37> 12/3/96 ted [1608989] Unhilite menu before find dialog <36> 11/26/96 ecs support GXGraphics extension; smarter cursor adjustment; delay menu unhiliting to provide more feedback <35> 9/9/96 dmp Fix my Homer with when to include qd <34> 9/9/96 dmp staticfy functions that are local to eliminate warnings in MWERKS compilers. Also fix the #ifdef on the qd globals. <33> 8/28/96 ted fixing errors on printing with abort <32> 8/21/96 ecs sometimes don't need QDGlobals <31> 7/24/96 ted fixing stupid ttro draw hook bug <30> 7/18/96 ted fixing menu nil dereference <29> 7/9/96 ted 1366267: menu bar flashing <28> 6/10/96 ted error dialog shouldn't use 7.x features on 6.x system <27> 6/5/96 ted removing hack code no longer needed for spell catcher <26> 6/4/96 ted for PPC, check symbols in addition to Gestalt <25> 5/31/96 ted adding UPPs for all printing message stuff <24> 5/31/96 ted adding PPC, FAT, and NuKernel builds <23> 5/29/96 ted don't assume window across WNE (sheash!) <22> 5/29/96 ted always finish event when front window isn't one we know about <21> 5/10/96 ted fixing possible infinite loop in quitting w/ non closable windows <20> 4/30/96 ted moving segments to initialize <19> 4/17/96 ted adding support for external guide files <18> 4/11/96 ted cwindowptr->windowptr <17> 4/10/96 ted don't close desk acc windows <16> 3/7/96 ted fixing print attempt for dragging things to DTPs <15> 2/15/96 ted adding qd for new libraries <14> 2/8/96 ted CountMenuItems->CountMItems (??) <13> 1/4/96 ecs resegment for threads <12> 1/4/96 ecs font menu & AG threads <11> 12/6/95 ted adding file type to prefligth <10> 11/13/95 ted don't close docs already open after print <9> 11/10/95 ted converting error dialog to moveable modal <8> 11/9/95 ted adding content region check for adjust cursor <7> 11/2/95 ted BlockMoveData <6> 10/31/95 ted testing some resolutions <5> 10/31/95 ted adding support for high-res pict scaling <4> 10/2/95 TD adding support for SC compiler <3> 9/15/95 Gr For contents menu support, make AdjustMenus and EnableCommand defensive against nil menu handles <2> 8/22/95 TD moving enum to simpletext.h <1> 8/21/95 TD First checked in. <61> 1/31/95 TED GX printing was removing too much from pages (#1214713) <60> 1/4/95 DAL Move the SetWTitle for "untitled" here from TextFile.c (to fix an Apple Menu Options problem, Radar #s 1207631 and 1207614). <59> 1/3/95 TED Radar #1166592. Don't touch justification in the right to left case. <58> 12/21/94 DAL Radar #1207643. Made AdjustScrollBars only show the controls if the owning window is hilited (for dragging text from another window). <57> 12/8/94 DAL Radar #1204706. Now handles updates behind GetFile dialogs (CustomGetFile, or CustomGetFilePreview if QuickTime is available). Also, the save-changes filter was handling keystrokes but wasn't updating windows. <50> 10/4/94 TED Window to front if doc already open (#116448). <49> 9/8/94 DAL AdjustMenus when last window is closed (#1148445). Added key shortcuts for the Don't Save button (#110047). Untitled window number increments only when appropriate (#1183083), resets when there are no windows open, and the first untitled window has no number (#1148458). We now handle updates behind the save-changes alert. */ #define TARGET_CARBON 1 #define ACCESSOR_CALLS_ARE_FUNCTIONS 1 #include "MacIncludes.h" #include <Appearance.h> #include <Controls.h> #include <ControlDefinitions.h> #include <ImageCompression.h> // for CustomGetFilePreview #include <Threads.h> #include <Components.h> // for AppleScript #include <OSA.h> // for AppleScript // #include "GraphicsImporter.h" #if ALLOW_QUICKTIME #include "QuickTimeComponents.h" #endif #define CompilingMain 1 #include "SimpleText.h" #include "Clipboard.h" #include <PMApplication.h> #define qSingleSelectionOnly 1 // MDK - for CARBON since we don't do AppleEvents through HighLevel events yet. // amount of time we leave a menu title hilited after a cmd key is used #define kMenuHiliteDelay 2 #define ff(x) ((Fixed)(x) << 16) // -------------------------------------------------------------------------------------------------------------- // FORWARD DECLARES // -------------------------------------------------------------------------------------------------------------- void UnhiliteMenuDelayed(unsigned long keyTime); OSErr DoActivate(WindowPtr pWindow, Boolean activating); OSErr DoCommand(WindowPtr pWindow, short commandID, long menuResult, long keyTime); OSErr DoKeyEvent(WindowPtr pWindow, EventRecord * pEvent, Boolean processPageControls); Boolean CommandToIDs(short commandID, short * menuID, short *itemID); Boolean AdjustMenus(WindowPtr pWindow, Boolean editDialogs, Boolean forceTitlesOn); static Boolean CloseAllWindows( Boolean quitting ); static void SynchronizeFiles( void ); // -------------------------------------------------------------------------------------------------------------- // GLOBAL VARIABLES // -------------------------------------------------------------------------------------------------------------- EventRecord gEvent; // currently pending event Boolean gAllDone; // true if the application is the in process of terminating Boolean gInModalState; // handling events with a modal dialog up MachineInfoRec gMachineInfo; // info about abilities and options installed on this machine short gApplicationResFile; // resource fork of application RgnHandle gCursorRgn; // region to control the cursor apearence #if !forCarbon AGRefNum gAGRefNum = -1; // AppleGuide database which is open FSSpec gAGSpec; // where to find our database AGCoachRefNum gAGCoachRefNum = -1; // coach handler refNum ThreadID gAGThread; // thread that looks for AppleGuide database #endif ThreadID gFontThread; // thread that builds font menu ThreadID gStarterThread; // starts our other threads for us Boolean gDontYield; // whether our threads should yield void* gThreadResults; // scratch space for thread results ComponentInstance gOSAComponent = NULL; // for AppleScript: connection to OSA scripting component // AEC, addded ControlActionUPP gVActionProc = NULL; ControlActionUPP gHActionProc = NULL; // These variables are for the find/replace commands Str255 gFindString = "\p", gReplaceString = "\p"; Boolean gWrapAround = false, gCaseSensitive = false; // Metrowerks MWCRuntime.lib defines qd for us on PPC, and their // __runtime module does under the 68K case. OTOH, neither SC nor // MrC give us qd for free, so we need it there. I'm still not // certain which way to go for the ThinkC or Symantec PPC case. #if !defined(__MWERKS__) // QuickDraw globals //QDGlobals qd; #endif // -------------------------------------------------------------------------------------------------------------- #pragma segment Utility #if 0 static pascal Boolean AlertFilter(DialogPtr theDialog, EventRecord *theEvent, short *itemHit) { if (theEvent->what == activateEvt && (DialogPtr) theEvent->message == theDialog) { SetDialogDefaultItem(theDialog, 1); } if (StdFilterProc(theDialog, theEvent, itemHit)) return true; // Pass updates through (Activates are tricky...was mucking with Apple menu & thereby // drastically changing how the system handles the menu bar during our alert) if (theEvent->what == updateEvt /* || theEvent->what == activateEvt */ ) { HandleEvent(theEvent); } return false; } // AlertFilter #endif void ConductErrorDialog(OSErr error, short commandID, short alertType) { long foundError; // The error, converted to a number short stringIndex; // Index into the strings Str255 errorText; // the error in a string format // Start with no error so far foundError = 0; // Start with the first string stringIndex = 1; // Loop until we find an error string errorText[0] = 0; do { // Get the string, and convert it to a number GetIndString(errorText, kErrorBaseID + commandID, stringIndex); if (errorText[0] == 0) break; StringToNum(errorText, &foundError); // If we reach the last string, or we match the error code if ((foundError == 0) || (foundError == error)) { // Get the text string for this error GetIndString(errorText, kErrorBaseID + commandID, stringIndex+1); } else { // Otherwise, make us continue until we get a string errorText[0] = 0; } // Advance so we get the next string number stringIndex += 2; } while (errorText[0] == 0); // errorText[0] == 0 if (errorText[0] != 0) { DialogPtr dPtr; short hit; Cursor arrow; SetCursor(GetQDGlobalsArrow(&arrow)); ParamText(errorText, "\p", "\p", "\p"); dPtr = GetNewDialog(kErrorBaseID + alertType, nil, (WindowPtr)-1); SetDialogDefaultItem(dPtr, ok); BeginMovableModal(); do { MovableModalDialog(nil, &hit); } while (hit != ok); DisposeDialog(dPtr); EndMovableModal(); } } // ConductErrorDialog // -------------------------------------------------------------------------------------------------------------- #pragma segment Utility static void MovableModalMenus(DialogPtr dPtr, short *pItem, long menuResult, long keyTime) { short iCut, iCopy, iClear, iPaste; short editMenu; short menuItem = menuResult & 0xFFFF; // find out where edit menus are CommandToIDs(cCut, &editMenu, &iCut); CommandToIDs(cCopy, &editMenu, &iCopy); CommandToIDs(cClear, &editMenu, &iClear); CommandToIDs(cPaste, &editMenu, &iPaste); UnhiliteMenuDelayed(keyTime); switch (menuResult >> 16) { case mApple: { #if(0) Str255 tempString; GetMenuItemText(GetMenuHandle(menuResult>>16), menuItem, tempString); OpenDeskAcc(tempString); #endif } break; case mEdit: { short type; Handle item; Rect box; short editField = GetDialogKeyboardFocusItem(dPtr); // return typed item, if it isn't disabled GetDialogItem(dPtr, editField, &type, &item, &box); if ((type & itemDisable) == 0) *pItem = editField; if (menuItem == iCut) { DialogCut(dPtr); ZeroScrap(); TEToScrap(); } if (menuItem == iCopy) { DialogCopy(dPtr); ZeroScrap(); TEToScrap(); } if (menuItem == iClear) DialogDelete(dPtr); if (menuItem == iPaste) DialogPaste(dPtr); } break; } } // MovableModalMenus // -------------------------------------------------------------------------------------------------------------- #pragma segment Utility void UnhiliteMenuDelayed(unsigned long keyTime) { if (keyTime != 0) { keyTime = TickCount() - keyTime; if (keyTime < kMenuHiliteDelay) Delay(kMenuHiliteDelay - keyTime, &keyTime); } HiliteMenu(0); } // -------------------------------------------------------------------------------------------------------------- #pragma segment Utility void MovableModalDialog(ModalFilterProcPtr filterProc, short *pItem) /* Call this as you would ModalDialog, when the dialog is moveable modal. However, first call BeginMovableModal, and afterwards (after disposing of dialog) call EndMovableModal. */ { GrafPtr curPort; DialogPtr dPtr = GetDialogFromWindow(FrontWindow()); RgnHandle structRegion = NewRgn(); *pItem = 0; if (dPtr) { GetPort(&curPort); SetPort(GetWindowPort(FrontWindow())); do { WaitNextEvent(mDownMask + mUpMask + keyDownMask + keyUpMask + autoKeyMask + updateMask + activMask + osMask, &gEvent, 0, nil); // call the filter proc if ( (filterProc) && ((*filterProc) (dPtr, &gEvent, pItem)) ) break; // call the basic filtering if (StdFilterProc(dPtr, &gEvent, pItem)) break; // handle keyboard if ((gEvent.what == keyDown || gEvent.what == autoKey) && (gEvent.modifiers & cmdKey)) { long result; long tck; result = MenuKey(gEvent.message & charCodeMask); tck = TickCount(); MovableModalMenus(dPtr, pItem, result, tck); break; } // handle clicks and drags if (gEvent.what == mouseDown) { WindowPtr whichWindow; short part = FindWindow(gEvent.where, &whichWindow); DialogPtr whichDialog = NULL; if (whichWindow) whichDialog = GetDialogFromWindow(whichWindow); // menu bar events if (part == inMenuBar) { InitCursor(); // make sure we've got an arrow during menu tracking MovableModalMenus(dPtr, pItem, MenuSelect(gEvent.where), 0); break; } // check for outside of our window GetWindowRegion( GetDialogWindow( dPtr ), kWindowStructureRgn, structRegion ); if (!PtInRgn(gEvent.where, structRegion)) { SysBeep(1); gEvent.what = nullEvent; } // drag the window around if ( (part == inDrag) && (whichDialog == dPtr) ) { Rect tempRect; DragWindow(whichWindow, gEvent.where, GetRegionBounds( GetGrayRgn(), &tempRect) ); gEvent.what = nullEvent; } } // check with standard dialog stuff { DialogPtr tempDialog; if ( IsDialogEvent(&gEvent) && DialogSelect(&gEvent, &tempDialog, pItem) ) break; } // handle updates if (gEvent.what == updateEvt) { HandleEvent(&gEvent); break; } } while (true); SetPort(curPort); } } // MovableModalDialog // -------------------------------------------------------------------------------------------------------------- #pragma segment Utility void BeginMovableModal(void) { DialogPtr dPtr = GetDialogFromWindow(FrontWindow()); WindowPtr nextWindow = GetNextWindow(FrontWindow()); // Disable the current indicator because the upcoming dialog is moveable modal HiliteMenu(0); if (nextWindow) DoActivate(nextWindow, false); AdjustMenus(GetDialogWindow(dPtr), (GetDialogKeyboardFocusItem(dPtr) > 0), false); } // BeginMovableModal // -------------------------------------------------------------------------------------------------------------- #pragma segment Utility void EndMovableModal(void) { WindowPtr nextWindow = FrontWindow(); AdjustMenus(nextWindow, true, false); if (nextWindow) DoActivate(nextWindow, true); } // EndMovableModal // -------------------------------------------------------------------------------------------------------------- #pragma segment Utility short ConductFindOrReplaceDialog(short dialogID) { DialogPtr dPtr; short hit; // menu shouldn't stay hilighted during the dialog HiliteMenu(0); dPtr = GetNewDialog(dialogID, nil, (WindowPtr)-1); if (dPtr) { short kind; Rect box; Handle item; // standard default behavior SetDialogDefaultItem(dPtr, ok); SetDialogCancelItem (dPtr, cancel); SetDialogTracksCursor(dPtr, true); // Find string GetDialogItem(dPtr, iFindEdit, &kind, &item, &box); SetDialogItemText(item, gFindString); // check boxes GetDialogItem(dPtr, iCaseSensitive, &kind, &item, &box); SetControlValue((ControlHandle)item, gCaseSensitive); GetDialogItem(dPtr, iWrapAround, &kind, &item, &box); SetControlValue((ControlHandle)item, gWrapAround); if (dialogID == kReplaceWindowID) { // Replace string GetDialogItem(dPtr, iReplaceEdit, &kind, &item, &box); SetDialogItemText(item, gReplaceString); } // select the search text by default SelectDialogItemText(dPtr, iFindEdit, 0, 32767); // and away we go! ShowWindow(GetDialogWindow(dPtr)); BeginMovableModal(); do { MovableModalDialog(nil, &hit); switch (hit) { case iCaseSensitive: case iWrapAround: GetDialogItem(dPtr, hit, &kind, &item, &box); SetControlValue((ControlHandle)item, 1-GetControlValue((ControlHandle)item)); break; } } while ( (hit != ok) && (hit != cancel) && (hit != iReplaceAll) ); if (hit != cancel) { // Find string GetDialogItem(dPtr, iFindEdit, &kind, &item, &box); GetDialogItemText(item, gFindString); // nothing to find is like a cancel if (gFindString[0] < 1) hit = cancel; // check boxes GetDialogItem(dPtr, iCaseSensitive, &kind, &item, &box); gCaseSensitive = GetControlValue((ControlHandle)item); GetDialogItem(dPtr, iWrapAround, &kind, &item, &box); gWrapAround = GetControlValue((ControlHandle)item); if (dialogID == kReplaceWindowID) { // Replace string GetDialogItem(dPtr, iReplaceEdit, &kind, &item, &box); GetDialogItemText(item, gReplaceString); } } DisposeDialog(dPtr); EndMovableModal(); } return(hit); } // ConductFindOrReplaceDialog // -------------------------------------------------------------------------------------------------------------- #pragma segment Utility void LocalToGlobalRgn(RgnHandle rgn) { Point offset; CGrafPtr thePort = GetQDGlobalsThePort(); Rect bounds; GetPortBounds(thePort, &bounds); offset = TopLeft(bounds); OffsetRgn(rgn, -offset.h, -offset.v); } // LocalToGlobalRgn // -------------------------------------------------------------------------------------------------------------- #pragma segment Utility void GlobalToLocalRgn(RgnHandle rgn) { Point offset; CGrafPtr thePort = GetQDGlobalsThePort(); Rect bounds; GetPortBounds(thePort, &bounds); offset = TopLeft(bounds); OffsetRgn(rgn, offset.h, offset.v); } // GlobalToLocalRgn // -------------------------------------------------------------------------------------------------------------- #pragma segment Utility void SetWatchCursor(void) { CursHandle theWatch; theWatch = MacGetCursor(watchCursor); if (theWatch) { char oldState; oldState = HGetState((Handle) theWatch); HLock((Handle) theWatch); SetCursor(*theWatch); HSetState((Handle) theWatch, oldState); } } // SetWatchCursor // -------------------------------------------------------------------------------------------------------------- #pragma segment Utility void LongRectToRect(LongRect* longRect, Rect *rect) { rect->top = longRect->top; rect->left = longRect->left; rect->bottom = longRect->bottom; rect->right = longRect->right; } // LongRectToRect // -------------------------------------------------------------------------------------------------------------- #pragma segment Utility void RectToLongRect(Rect *rect, LongRect *longRect) { longRect->top = rect->top; longRect->left = rect->left; longRect->bottom = rect->bottom; longRect->right = rect->right; } // RectToLongRect // -------------------------------------------------------------------------------------------------------------- #pragma segment Utility void GetPICTRectangleAt72dpi(PicHandle hPicture, Rect *pictureRect) { typedef struct FixedRect { Fixed left; Fixed top; Fixed right; Fixed bottom; } FixedRect; typedef struct { Picture pictInfo; unsigned short versionOp; // 0x1101 Byte opCodes[1]; } PICTHeaderVer1; typedef struct { Picture pictInfo; unsigned short versionOp; // 0x0011 unsigned short versionOp2; // 0x02ff unsigned short headerOp; // 0x0c00 unsigned short version; // 0xffff unsigned short version2; // 0xffff FixedRect pictBounds; unsigned long reserved; unsigned short opCodes[1]; } PICTHeaderVer2; typedef struct { Picture pictInfo; unsigned short versionOp; // 0x0011 unsigned short versionOp2; // 0x02ff unsigned short headerOp; // 0x0c00 unsigned short version; // 0xfffe unsigned short reserved; // 0x0000 Fixed hRes; Fixed vRes; Rect pictBounds; unsigned long reserved2; unsigned short opCodes[1]; } PICTHeaderVer2Ext; Fixed hRes, vRes; PICTHeaderVer1* pPict = (PICTHeaderVer1*) *hPicture; Rect srcRect = (**hPicture).picFrame; hRes = vRes = ff(72); // assume 72 dpi if (pPict->versionOp == 0x0011) { // Version 2 PICT PICTHeaderVer2* pPict2 = (PICTHeaderVer2*) pPict; if (pPict2->version == 0xfffe) { // Extended Version 2 PICTHeaderVer2Ext* pPict2ext = (PICTHeaderVer2Ext*) pPict; hRes = pPict2ext->hRes; vRes = pPict2ext->vRes; srcRect = pPict2ext->pictBounds; } } hRes = FixDiv(hRes, ff(72)); vRes = FixDiv(vRes, ff(72)); pictureRect->left = Fix2Long(FixDiv( ff(srcRect.left), hRes )); pictureRect->right = Fix2Long(FixDiv( ff(srcRect.right), hRes )); pictureRect->top = Fix2Long(FixDiv( ff(srcRect.top), vRes )); pictureRect->bottom = Fix2Long(FixDiv( ff(srcRect.bottom), vRes )); } // GetPICTRectangleAt72dpi // -------------------------------------------------------------------------------------------------------------- #pragma segment Utility static WindowDataPtr GetWindowInfo(WindowPtr pWindow) { WindowDataPtr result = nil; if ( (pWindow) && (GetWindowKind(pWindow) == userKind) ) result = (WindowDataPtr) GetWRefCon(pWindow); return result; } // GetWindowInfo // -------------------------------------------------------------------------------------------------------------- #pragma segment Utility static short ZeroStringSub(Str255 destString, Str255 subStr) // returns number of substitutions performed { OSErr anErr; Handle destHandle = nil; Handle subHandle = nil; short count = 0; anErr = PtrToHand(&destString[1], &destHandle, destString[0]); if (anErr == noErr) { anErr = PtrToHand(&subStr[1], &subHandle, subStr[0]); if (anErr == noErr) { count = ReplaceText(destHandle, subHandle, "\p^0"); // error or # of substitutions destString[0] = GetHandleSize(destHandle); BlockMoveData(*destHandle, &destString[1], destString[0]); } } DisposeHandle(destHandle); DisposeHandle(subHandle); if (count < 0) count = 0; // change error code into count = 0 substitutions return count; } // ZeroStringSub // -------------------------------------------------------------------------------------------------------------- // BEGIN SCROLL ACTION PROCS // -------------------------------------------------------------------------------------------------------------- #pragma segment Main void SetControlAndClipAmount(ControlHandle control, short * amount) { short value, max; value = GetControlValue(control); /* get current value */ max = GetControlMaximum(control); /* and maximum value */ *amount = value - *amount; if ( *amount < 0 ) *amount = 0; else { if ( *amount > max ) *amount = max; } SetControlValue(control, *amount); *amount = value - *amount; /* calculate the real change */ } // SetControlAndClipAmount // -------------------------------------------------------------------------------------------------------------- static pascal void VActionProc(ControlHandle control, short part) { if (part != 0) { WindowPtr pWindow = GetControlOwner(control); WindowDataPtr pData = GetWindowInfo(pWindow); short amount = 0; switch (part) { case kControlUpButtonPart: amount = pData->vScrollAmount; SetControlAndClipAmount(control, &amount); break; case kControlDownButtonPart: amount = -pData->vScrollAmount; SetControlAndClipAmount(control, &amount); break; // vertical page scrolling should be a multiple of the incremental scrolling -- so that // we avoid half-lines of text at the bottom of pages. // More generically, if there was a method for dealing with text scrolling by a non-constant // amount, this would be better -- but SimpleText currently doesn't have a framework to allow // the document object to override the scroll amount dynamically. Maybe something to add in // the future. case kControlPageUpPart: amount = (((pData->contentRect.bottom - pData->contentRect.top) / pData->vScrollAmount)-1) * pData->vScrollAmount; if (amount == 0) amount = pData->contentRect.bottom - pData->contentRect.top; SetControlAndClipAmount(control, &amount); break; case kControlPageDownPart: amount = (((pData->contentRect.top - pData->contentRect.bottom) / pData->vScrollAmount)+1) * pData->vScrollAmount; if (amount == 0) amount = pData->contentRect.top - pData->contentRect.bottom; SetControlAndClipAmount(control, &amount); break; default: amount = pData->oldVValue - GetControlValue(control); pData->oldVValue = GetControlValue(control); break; } DoScrollContent(pWindow, pData, 0, amount); } } // VActionProc // -------------------------------------------------------------------------------------------------------------- static pascal void HActionProc(ControlHandle control, short part) { if (part != 0) { WindowPtr pWindow = GetControlOwner(control); WindowDataPtr pData = GetWindowInfo(pWindow); short amount = 0; switch (part) { case kControlUpButtonPart: amount = pData->hScrollAmount; SetControlAndClipAmount(control, &amount); break; case kControlDownButtonPart: amount = -pData->hScrollAmount; SetControlAndClipAmount(control, &amount); break; case kControlPageUpPart: amount = pData->contentRect.right - pData->contentRect.left; SetControlAndClipAmount(control, &amount); break; case kControlPageDownPart: amount = pData->contentRect.left - pData->contentRect.right; SetControlAndClipAmount(control, &amount); break; default: amount = pData->oldHValue - GetControlValue(control); pData->oldHValue = GetControlValue(control); break; } DoScrollContent(pWindow, pData, amount, 0); } } // HActionProc // -------------------------------------------------------------------------------------------------------------- // END SCROLL ACTION PROCS // -------------------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------------------- // SEARCH/REPLACE UTILITY FUNCTIONS // -------------------------------------------------------------------------------------------------------------- static Boolean IsThisTheString( Ptr p, // pointer to check Str255 searchString, // string to check for Boolean isCaseSensitive) // case sensitive check or not /* Returns true if the supplied string is at the specified offset. Otherwise returns false. */ { Boolean returnValue = false; if (isCaseSensitive) returnValue = ( IUMagString(p, &searchString[1], searchString[0], searchString[0]) == 0 ); else returnValue = ( IUMagIDString(p, &searchString[1], searchString[0], searchString[0]) == 0 ); return(returnValue); } // IsThisTheString // -------------------------------------------------------------------------------------------------------------- Boolean PerformSearch( Handle h, // handle to search long start, // offset to begin with Str255 searchString, // string to search for Boolean isCaseSensitive, // case sensitive search Boolean isBackwards, // search backwards from starting point Boolean isWraparound, // wrap search around from end->begining long * pNewStart, // returned new selection start long * pNewEnd) // returned new selection end /* Performs a search on the supplied handle, starting at the provided offset. Returns the new selection start and end values, and true if the search is successful. Otherwise it returns false. */ { char flags; Ptr startPtr; Ptr endPtr; Ptr searchPtr; Boolean foundIt = false; flags = HGetState(h); HLock(h); // back up one when searching backwards, or we'll hit every time on the current // character if (isBackwards) { if (start != 0) { --start; } else { if (isWraparound) start = GetHandleSize(h); else return(false); } } // determine the bounds of the searching startPtr = (*h) + start; if ( isWraparound ) { if (isBackwards) { // go backwards until just after the start, or begining of // document is start is the end if (start == GetHandleSize(h)) endPtr = *h; else endPtr = startPtr + 1; } else { // go forwards until just before the start, or to the end // of the document is the start is already the begining if (start == 0) endPtr = *h + GetHandleSize(h); else endPtr = startPtr - 1; } } else { if (isBackwards) { // go back until hit begining of document endPtr = *h-1; } else { // go forward until hit end of document endPtr = *h + GetHandleSize(h); } } searchPtr = startPtr; while (searchPtr != endPtr) { short byteType; byteType = CharacterByteType(startPtr, searchPtr - startPtr, smCurrentScript); if ( ((byteType == smSingleByte) || (byteType == smFirstByte)) && IsThisTheString(searchPtr, searchString, isCaseSensitive) ) { foundIt = true; *pNewStart = searchPtr - *h; *pNewEnd = *pNewStart + searchString[0]; break; } if (isBackwards) --searchPtr; else ++searchPtr; if (isWraparound) { if (searchPtr < *h) searchPtr = *h + GetHandleSize(h); if (searchPtr > *h + GetHandleSize(h)) searchPtr = *h; } } HSetState(h, flags); return(foundIt); } // PerformSearch // -------------------------------------------------------------------------------------------------------------- // SELECTION UTILITY ROUTINES // -------------------------------------------------------------------------------------------------------------- void DrawSelection(WindowDataPtr pData, Rect *pSelection, short * pPhase, Boolean bumpPhase) { if (!EmptyRect(pSelection) ) { RgnHandle oldClip = NewRgn(); Pattern aPattern; Rect newClip; if ( (bumpPhase) && (MOVESELECTION(TickCount()) ) ) { if ((++(*pPhase)) > 7 ) *pPhase = 1; } // setup for drawing in this window SetPort((GrafPtr) pData); GetClip(oldClip); PenMode(notPatXor); // offset the draw area (SetOrigin a must to preserve pattern appearence) // and the clip area to avoid stepping on the scroll bars SetOrigin(GetControlValue(pData->hScroll), GetControlValue(pData->vScroll)); newClip = pData->contentRect; OffsetRect(&newClip, GetControlValue(pData->hScroll), GetControlValue(pData->vScroll)); ClipRect(&newClip); // do the draw GetIndPattern(&aPattern, kPatternListID, (*pPhase)+1); PenPat(&aPattern); FrameRect(pSelection); SetOrigin(0, 0); // restore the old port settings SetClip(oldClip); DisposeRgn(oldClip); PenNormal(); } } // DrawSelection // -------------------------------------------------------------------------------------------------------------- OSErr SelectContents(WindowPtr pWindow, WindowDataPtr pData, EventRecord *pEvent, Rect *pSelection, Rect *pContent, short *pPhase) { OSErr anErr = noErr; Point clickPoint = pEvent->where; Point currentPoint; Boolean didJustScroll; ControlHandle theControl; GlobalToLocal(&clickPoint); if (FindControl(clickPoint, pWindow, &theControl) == 0) { // move the click point into the proper range clickPoint.h += GetControlValue(pData->hScroll); clickPoint.v += GetControlValue(pData->vScroll); // if the shift key is held down then the selection starts from // a preexisting point such that we are doing an expand/contract // of the original selection if (pEvent->modifiers & shiftKey) { if (clickPoint.h < pSelection->right) clickPoint.h = pSelection->right; else clickPoint.h = pSelection->left; if (clickPoint.v < pSelection->bottom) clickPoint.v = pSelection->bottom; else clickPoint.v = pSelection->top; } while (StillDown()) { CGrafPtr thePort = GetQDGlobalsThePort(); // get the current mouse GetMouse(¤tPoint); didJustScroll = false; // scroll contents if needed { short deltaH = 0; short deltaV = 0; Rect bounds; GetPortBounds(thePort, &bounds); if (currentPoint.h < 0) deltaH = pData->hScrollAmount; if (currentPoint.h > bounds.right) deltaH = -pData->hScrollAmount; if (currentPoint.v < 0) deltaV = pData->vScrollAmount; if (currentPoint.v > bounds.bottom) deltaV = -pData->vScrollAmount; if ( (deltaH != 0) || (deltaV != 0) ) { if (deltaH) SetControlAndClipAmount(pData->hScroll, &deltaH); if (deltaV) SetControlAndClipAmount(pData->vScroll, &deltaV); DoScrollContent(pWindow, pData, deltaH, deltaV); didJustScroll = true; } } // map mouse into proper range currentPoint.h += GetControlValue(pData->hScroll); currentPoint.v += GetControlValue(pData->vScroll); // clip to the document size if (currentPoint.h < 0) currentPoint.h = 0; if (currentPoint.v < 0) currentPoint.v = 0; if (currentPoint.h > pContent->right) currentPoint.h = pContent->right; if (currentPoint.v > pContent->bottom) currentPoint.v = pContent->bottom; // draw the new selection if it is time or we are about to // exit this loop if ((MOVESELECTION(TickCount())) || (!Button()) || (didJustScroll) ) { // first, erase any old selection we might have had DrawSelection(pData, pSelection, pPhase, false); // make a rectangle out of the two points pSelection->left = Min(currentPoint.h, clickPoint.h); pSelection->right = Max(currentPoint.h, clickPoint.h); pSelection->top = Min(currentPoint.v, clickPoint.v); pSelection->bottom = Max(currentPoint.v, clickPoint.v); // draw the new selection DrawSelection(pData, pSelection, pPhase, true); } } // we handled the selection anErr = eActionAlreadyHandled; } return(anErr); } // SelectContents // -------------------------------------------------------------------------------------------------------------- void DragAndDropArea(WindowPtr pWindow, WindowDataPtr pData, EventRecord* event, Rect *pFrameRect) { RgnHandle hilightRgn; DragReference theDrag; OSErr anErr = noErr; if (NewDrag(&theDrag) == noErr) { // add the flavor for the window title, errors can be ignored as this // is a cosmetic addition { enum { kFlavorTypeClippingName = 'clnm' }; Str255 windowTitle; GetWTitle(pWindow, windowTitle); (void) AddDragItemFlavor(theDrag, 1, kFlavorTypeClippingName, &windowTitle, windowTitle[0]+1, flavorNotSaved); } if (pData->pDragAddFlavors) anErr = (*(pData->pDragAddFlavors)) (pWindow, pData, theDrag); if (anErr == noErr) { Rect globalRect = *pFrameRect; hilightRgn = NewRgn(); LocalToGlobal(&TopLeft(globalRect)); LocalToGlobal(&BotRight(globalRect)); RectRgn(hilightRgn, &globalRect); SetDragItemBounds(theDrag, 1, &globalRect); // turn the region from a fill into a frame { RgnHandle tempRgn = NewRgn(); CopyRgn(hilightRgn, tempRgn); InsetRgn(tempRgn, 1, 1); DiffRgn(hilightRgn, tempRgn, hilightRgn); DisposeRgn(tempRgn); } TrackDrag(theDrag, event, hilightRgn); DisposeDrag(theDrag); DisposeRgn(hilightRgn); } } } // DragAndDropArea // -------------------------------------------------------------------------------------------------------------- // WINDOW UTILITY ROUTINES // -------------------------------------------------------------------------------------------------------------- #pragma segment Main static void CalculateGrowIcon(WindowPtr pWindow,WindowDataPtr pData, Rect * location) { #pragma unused (pWindow) Rect bounds; if (pData->vScroll) { GetControlBounds(pData->vScroll, &bounds); location->top = bounds.bottom; } else { if (pData->hScroll) { GetControlBounds(pData->hScroll, &bounds); location->top = bounds.top; } else { GetWindowPortBounds(pData->theWindow, &bounds); location->top = bounds.bottom - 15; } } if (pData->hScroll) { GetControlBounds(pData->hScroll, &bounds); location->left = bounds.right; } else { if (pData->vScroll) { GetControlBounds(pData->vScroll, &bounds); location->left = bounds.left; } else { GetWindowPortBounds(pData->theWindow, &bounds); location->left = bounds.right - 15; } } location->right = location->left + 16; location->bottom = location->top + 16; } // CalculateGrowIcon // -------------------------------------------------------------------------------------------------------------- #pragma segment Main // // Set the modified bit for the window // void SetDocumentContentChanged( WindowDataPtr pData, Boolean changed ) { pData->changed = changed; if( gMachineInfo.haveProxyIcons ) SetWindowModified( pData->theWindow, changed ); } // -------------------------------------------------------------------------------------------------------------- #pragma segment Main OSErr AdjustScrollBars(WindowRef pWindow, Boolean moveControls, // might the controls have moved? Boolean didResize, // did we just resize the window? Boolean *needInvalidate) // does the caller need to invalidate contents as a result? { OSErr anErr = noErr; LongRect docRect; WindowDataPtr pData = GetWindowInfo(pWindow); Rect growIconRect; if (needInvalidate) *needInvalidate = false; if (pData) { short oldHMax = 0; short oldVMax = 0; short oldHValue = 0; short oldVValue = 0; Rect bounds; // cache current values, we'll force an update if we needed to change em! if (pData->hScroll) { oldHMax = GetControlMaximum(pData->hScroll); oldHValue = GetControlValue(pData->hScroll); } if (pData->vScroll) { oldVMax = GetControlMaximum(pData->vScroll); oldVValue = GetControlValue(pData->vScroll); } // if we have a grow box but not all controls we have to invalidate the grow bar areas // by caclulating them if ( (didResize) && (pData->hasGrow) ) { GetWindowPortBounds(pWindow, &bounds); // if we regrow without any scroll bars, we need to update the content area if ( (needInvalidate) && (pData->hScroll == nil) && (pData->vScroll == nil) ) *needInvalidate = true; // invalidate old grow bar areas if (pData->vScroll == nil) { growIconRect = bounds; growIconRect.left = pData->contentRect.right; InvalWindowRect(pWindow,&growIconRect); } if (pData->hScroll == nil) { growIconRect = bounds; growIconRect.top = pData->contentRect.bottom; InvalWindowRect(pWindow,&growIconRect); } // invalidate new grow bar areas if (pData->vScroll == nil) { growIconRect = bounds; growIconRect.left = growIconRect.right - kScrollBarSize; InvalWindowRect(pWindow,&growIconRect); } if (pData->hScroll == nil) { growIconRect = bounds; growIconRect.top = growIconRect.bottom - kScrollBarSize; InvalWindowRect(pWindow,&growIconRect); } } // if the controls need moving, recalculate the visible area if (moveControls) { growIconRect = bounds; if ((pData->hScroll) || (pData->hasGrow) ) pData->contentRect.bottom -= kScrollBarSize; if ((pData->vScroll) || (pData->hasGrow) ) pData->contentRect.right -= kScrollBarSize; } // before doing anything, make the controls invisible if (pData->hScroll) SetControlVisibility(pData->hScroll, false, false); if (pData->vScroll) SetControlVisibility(pData->vScroll, false, false); // based on document and visiable area, adjust possible control values if ( (pData->pGetDocumentRect) && ((pData->hScroll) || (pData->vScroll)) ) { // let the object calc the size and content if it wishes to anErr = (*(pData->pGetDocumentRect)) (pWindow, pData, &docRect, false); if (anErr == noErr) { short amountOver; short newMax; amountOver = (docRect.right - docRect.left) - (pData->contentRect.right - pData->contentRect.left); if ( (pData->hScroll) && (amountOver > 0) ) newMax = amountOver; else newMax = 0; if (pData->hScroll) { if (GetControlValue(pData->hScroll) > newMax) { if (needInvalidate) *needInvalidate = true; } SetControlMaximum(pData->hScroll, newMax); } amountOver = (docRect.bottom - docRect.top) - (pData->contentRect.bottom - pData->contentRect.top); if ( (pData->vScroll) && (amountOver > 0) ) newMax = amountOver; else newMax = 0; if (pData->vScroll) { if (GetControlValue(pData->vScroll) > newMax) { if (needInvalidate) *needInvalidate = true; } SetControlMaximum(pData->vScroll, newMax); } } } // then, if the controls need moving, we move them and inval the old // and new locations if (moveControls) { // if we have grow box we invalidate the old grow location if ( pData->hasGrow) { CalculateGrowIcon(pWindow, pData, &growIconRect); InvalWindowRect(pWindow,&growIconRect); } if (pData->hScroll) { short widthAdjust; Rect bounds; if ((pData->vScroll) || (pData->hasGrow)) widthAdjust = -kGrowScrollAdjust; else widthAdjust = -1; GetControlBounds(pData->hScroll, &bounds); InvalWindowRect( pWindow, &bounds); GetWindowPortBounds(pWindow, &bounds); MoveControl(pData->hScroll, pData->hScrollOffset - 1, bounds.bottom - kScrollBarSize); SizeControl(pData->hScroll, (bounds.right - bounds.left) + widthAdjust - pData->hScrollOffset, 16); GetControlBounds(pData->hScroll, &bounds); InvalWindowRect( pWindow, &bounds); } if (pData->vScroll) { short heightAdjust; if ((pData->hScroll) || (pData->hasGrow)) heightAdjust = -kGrowScrollAdjust; else heightAdjust = -1; GetControlBounds(pData->vScroll, &bounds); InvalWindowRect( pWindow, &bounds); GetWindowPortBounds(pWindow, &bounds); MoveControl(pData->vScroll, bounds.right - kScrollBarSize, pData->vScrollOffset-1); SizeControl(pData->vScroll, 16, (bounds.bottom - bounds.top) + heightAdjust - pData->vScrollOffset); GetControlBounds(pData->vScroll, &bounds); InvalWindowRect( pWindow, &bounds); } // if we have scroll bars, update the grow icon if ( pData->hasGrow ) { CalculateGrowIcon(pWindow,pData, &growIconRect); InvalWindowRect(pWindow,&growIconRect); } } // let the document adjust anything it needs to if (pData->pAdjustSize) anErr = (*(pData->pAdjustSize)) (pWindow, pData, &didResize); if ((didResize) && (needInvalidate)) *needInvalidate = true; if ( IsWindowHilited(pWindow) ) { // after doing something, make the controls visible if (pData->hScroll) { if ((oldHMax != GetControlMaximum(pData->hScroll)) || (oldHValue != GetControlValue(pData->hScroll)) ) ShowControl(pData->hScroll); else SetControlVisibility(pData->hScroll, true, false); } if (pData->vScroll) { if ((oldVMax != GetControlMaximum(pData->vScroll)) || (oldVValue != GetControlValue(pData->vScroll)) ) ShowControl(pData->vScroll); else SetControlVisibility(pData->vScroll, true, false); } } } return anErr; } // AdjustScrollBars // -------------------------------------------------------------------------------------------------------------- // MENU UTILITY ROUTINES // -------------------------------------------------------------------------------------------------------------- #pragma segment Main Boolean CommandToIDs(short commandID, short * menuID, short *itemID) { short ** commandHandle; short whichMenu; short oldResFile = CurResFile(); Boolean returnValue = false; UseResFile(gApplicationResFile); for (whichMenu = mApple; whichMenu <= mLastMenu; whichMenu++) { commandHandle = (short**) Get1Resource('MCMD', whichMenu); if (commandHandle) { short * pCommands = *commandHandle; short commandIndex; short numCommands = pCommands[0]; for (commandIndex = 1; commandIndex <= numCommands; ++commandIndex) if (pCommands[commandIndex] == commandID) { *menuID = whichMenu; *itemID = commandIndex; returnValue = (commandIndex == numCommands); } } } UseResFile(oldResFile); return returnValue; } // CommandToIDs // -------------------------------------------------------------------------------------------------------------- #pragma segment Main Boolean IsCommandEnabled(short commandID) /* returns true if a given command is currently enabled */ { short whichMenu, whichItem; MenuHandle menu; CommandToIDs(commandID, &whichMenu, &whichItem); menu = GetMenuHandle(whichMenu); if (IsMenuItemEnabled(menu, whichItem)) return(true); return(false); } // IsCommandEnabled // -------------------------------------------------------------------------------------------------------------- #pragma segment Main void EnableCommand(short commandID) /* Given a command ID, enables the first menu item with that command ID. If the command table for a given menu is less than the number of items in the menu, and the command being enabled is the last item in the command table, then all items from there on down are also enabled. This is useful for menus that get appended to, such as the desk accessory list, font list, or speaking voices list. */ { short whichMenu; short whichItem; if (CommandToIDs(commandID, &whichMenu, &whichItem)) { short i; MenuHandle menu = GetMenuHandle(whichMenu); if (menu) { short numItems = CountMItems(menu); for (i = whichItem; i <= numItems; ++i) EnableMenuItem(menu, i); } } else { MenuHandle menu = GetMenuHandle(whichMenu); if (menu) EnableMenuItem(menu, whichItem); } } // EnableCommand // -------------------------------------------------------------------------------------------------------------- #pragma segment Main void ChangeCommandName(short commandID, short resourceID, short resourceIndex) { short whichMenu; short whichItem; MenuHandle menu; // figure out how this command maps into the menu bar CommandToIDs(commandID, &whichMenu, &whichItem); menu = GetMenuHandle(whichMenu); // then make this item into the requested new string { Str255 theString; GetIndString(theString, resourceID, resourceIndex); SetMenuItemText(menu, whichItem, theString); } } // ChangeCommandName // -------------------------------------------------------------------------------------------------------------- #pragma segment Main void EnableCommandCheck(short commandID, Boolean check) { short whichMenu; short whichItem; if (CommandToIDs(commandID, &whichMenu, &whichItem)) { short i; MenuHandle menu = GetMenuHandle(whichMenu); short numItems = CountMItems(menu); for (i = whichItem; i <= numItems; ++i) { EnableMenuItem(menu, i); CheckItem(menu, i, check); } } else { MenuHandle menu = GetMenuHandle(whichMenu); EnableMenuItem(menu, whichItem); CheckItem(menu, whichItem, check); } } // EnableCommandCheck // -------------------------------------------------------------------------------------------------------------- #pragma segment Main void EnableCommandCheckStyle(short commandID, Boolean check, short style) { short whichMenu; short whichItem; if (CommandToIDs(commandID, &whichMenu, &whichItem)) { short i; MenuHandle menu = GetMenuHandle(whichMenu); short numItems = CountMItems(menu); for (i = whichItem; i <= numItems; ++i) { EnableMenuItem(menu, i); CheckItem(menu, i, check); SetItemStyle(menu, i, style); } } else { MenuHandle menu = GetMenuHandle(whichMenu); EnableMenuItem(menu, whichItem); CheckItem(menu, whichItem, check); SetItemStyle(menu, whichItem, style); } } // EnableCommandCheckStyle // -------------------------------------------------------------------------------------------------------------- #pragma segment Main static void DisableEntireMenu(MenuHandle menu); static void DisableEntireMenu(MenuHandle menu) { SInt16 i, count; count = CountMItems(menu); for (i = 0; i <= count; i++) { DisableMenuItem(menu, i); } } static Boolean IsAnyMenuItemEnabled(MenuHandle menu); static Boolean IsAnyMenuItemEnabled(MenuHandle menu) { SInt16 i, count; count = CountMItems(menu); for (i = 1; i <= count; i++) { if (IsMenuItemEnabled(menu, i)) return(true); } return(false); } Boolean AdjustMenus(WindowPtr pWindow, Boolean editDialogs, Boolean forceTitlesOn) { Boolean wasEnabled[mNumberMenus]; // Old state of menus MenuHandle menus[mNumberMenus]; short whichMenu; // for stepping through menus MenuHandle menu; // for reading in menu IDs WindowDataPtr pData = GetWindowInfo(pWindow); // Step through all of the menus for (whichMenu = mApple; whichMenu <= mLastMenu; whichMenu++) { // Save the old state of the menu title menus[whichMenu - mApple] = menu = GetMenuHandle(whichMenu); if (menu) // because contents menu may not be around { if (forceTitlesOn) wasEnabled[mLastMenu - whichMenu] = false; else wasEnabled[mLastMenu - whichMenu] = IsMenuItemEnabled(menu, 0); // Disable the entire menu DisableEntireMenu(menu); } } // select all, unless someone else changes it ChangeCommandName(cSelectAll, kMiscStrings, iSelectAllCommand); // if we have NO windows, or the current window is one we understand if ((pWindow == nil) || (pData)) { // enable the default commands EnableCommand(cAbout); EnableCommand(cDeskAccessory); EnableCommand(cNew); EnableCommand(cOpen); EnableCommand(cQuit); EnableCommand(cShowClipboard); } else { // it's printing or a dialog, so enable cut/copy/paste if (editDialogs) { EnableCommand(cCut); EnableCommand(cCopy); EnableCommand(cPaste); EnableCommand(cClear); } // and desk accs too! EnableCommand(cDeskAccessory); } if ( (pWindow) && (pData) ) { // all windows can be closed if (FrontWindow()) EnableCommand(cClose); // changed documents can be saved, but only if the file is open for write if ( (pData->changed) && ((pData->isWritable) || (pData->dataRefNum == -1)) ) EnableCommand(cSave); // objects with a print method can be printed and page setup-ed if (pData->pPrintPage) { EnableCommand(cPrint); EnableCommand(cPageSetup); EnableCommand(cPrintOneCopy); } // let object enable anything else that needs to be enabled if (pData->pAdjustMenus) (*(pData->pAdjustMenus)) (pWindow, pData); } // Now determine if any of the menus have changed state { Boolean gotToRedraw = false; for (whichMenu = mApple; whichMenu <= mLastMenu; ++whichMenu) { menu = menus[whichMenu - mApple]; if (menu) // because contents menu may not be around { // If any of the menu is enabled if (IsAnyMenuItemEnabled(menu)) { // Make sure to turn on the menu title EnableMenuItem(menu, 0); } /* If this new state is different than the saved state, then the menu bar will need to be redrawn */ if (wasEnabled[mLastMenu - whichMenu] != IsMenuItemEnabled(menu, 0)) { gotToRedraw = true; } } } // And if any titles have changed state, redraw them if (gotToRedraw) DrawMenuBar(); return gotToRedraw; } } // AdjustMenus // -------------------------------------------------------------------------------------------------------------- // FILE UTILITY ROUTINES // -------------------------------------------------------------------------------------------------------------- #pragma segment Utility static Boolean BringToFrontIfOpen(FSSpecPtr pSpec) { WindowPtr pWindow; pWindow = FrontWindow(); while (pWindow) { WindowDataPtr pData = GetWindowInfo(pWindow); if ( (pData) && (pData->fileSpec.vRefNum == pSpec->vRefNum) && (pData->fileSpec.parID == pSpec->parID) && EqualString(pData->fileSpec.name, pSpec->name, false, false) ) { SelectWindow(pWindow); return true; } pWindow = GetNextWindow(pWindow); } return false; } // BringToFrontIfOpen // -------------------------------------------------------------------------------------------------------------- #pragma segment Utility static Boolean BringToFrontIfExists(ResType windowKind) { WindowPtr pWindow; pWindow = FrontWindow(); while (pWindow) { WindowDataPtr pData = GetWindowInfo(pWindow); if ((pData) && (pData->windowKind == windowKind)) { SelectWindow(pWindow); return true; } pWindow = GetNextWindow(pWindow); } return false; } // BringToFrontIfExists // -------------------------------------------------------------------------------------------------------------- // MAIN SIMPLETEXT ROUTINES // -------------------------------------------------------------------------------------------------------------- #pragma segment Main static OSErr MakeNewWindow(ResType windowKind, FSSpecPtr fileSpec, OSType fileType, Boolean *pWasAlreadyOpen) { OSErr anErr = fnfErr; PreflightRecord thePreflight; PreflightWindowProc pPreflight = nil; WindowPtr pWindow; WindowDataPtr pData; ControlHandle rootControl; // require a certain amount of RAM free before we allow the new window to be created if (FreeMem() < kRAMNeededForNew) anErr = memFullErr; // make sure we update the cursor SetEmptyRgn(gCursorRgn); // <50> if we already have a document open from this file, bring the window to the // front and return with no error if ( (fileSpec) && (fileType != 'sEXT') && (BringToFrontIfOpen(fileSpec)) ) { if (pWasAlreadyOpen) *pWasAlreadyOpen = true; anErr = noErr; return(anErr); } if (pWasAlreadyOpen) *pWasAlreadyOpen = false; if (anErr != fnfErr) { nrequire(anErr, SanityCheckFailed); } // initialize our behavior thePreflight.continueWithOpen = true; thePreflight.resourceID = kDefaultWindowID; thePreflight.wantHScroll = false; thePreflight.wantVScroll = false; thePreflight.storageSize = sizeof(WindowDataRecord); thePreflight.makeProcPtr = nil; thePreflight.openKind = fsRdPerm; thePreflight.needResFork = false; thePreflight.doZoom = false; thePreflight.fileType = fileType; switch (windowKind) { case kAboutWindow: pPreflight = AboutPreflightWindow; break; case kPICTWindow: pPreflight = PICTPreflightWindow; break; #if ALLOW_QUICKTIME case kMovieWindow: pPreflight = MoviePreflightWindow; break; #endif case kClipboardWindow: pPreflight = ClipboardPreflightWindow; break; case kTextWindow: pPreflight = TextPreflightWindow; break; #if ALLOW_QUICKTIME case kThreeDWindow: pPreflight = ThreeDPreflightWindow; break; #endif } // preflight the window if (pPreflight) anErr = (*pPreflight) (&thePreflight); nrequire(anErr, PreflightFailed); if (thePreflight.continueWithOpen) { // allocate a place for the window pData = (WindowDataPtr)NewPtrClear(thePreflight.storageSize); anErr = MemError(); nrequire(anErr, FailedToAllocateWindow); // then actually create the window pWindow = GetNewCWindow(thePreflight.resourceID, NULL, (WindowPtr)-1); if (!pWindow) anErr = memFullErr; nrequire(anErr, NewWindowFailed); pData->theWindow = pWindow; SetWRefCon(pWindow, (long) pData); if (gMachineInfo.haveAppearanceMgr) CreateRootControl(pWindow, &rootControl); // zoom the rectangle to big size on this monitor // based upon which scroll bars they want { Rect rect; Rect bigRect; GetWindowPortBounds(pWindow, &rect); bigRect = (**GetMainDevice()).gdRect; bigRect.top += GetMBarHeight() * 2; bigRect.left += 4; bigRect.bottom -= 4; bigRect.right -= 65; SetPort((GrafPtr) GetWindowPort(pWindow)); LocalToGlobal(&TopLeft(rect)); LocalToGlobal(&BotRight(rect)); if ( (thePreflight.wantHScroll) || (thePreflight.doZoom) ) { // now that we auto stagger, we don't need this line //rect.left = bigRect.left; rect.right = bigRect.right; } if ( (thePreflight.wantVScroll) || (thePreflight.doZoom) ) { // now that we auto stagger, we don't need this line //rect.top = bigRect.top; rect.bottom = bigRect.bottom; } // can't have an invalid rectangle if (rect.right - rect.left < 32) rect.right = rect.left + 32; MoveWindow(pWindow, rect.left, rect.top, false); SizeWindow(pWindow, rect.right - rect.left, rect.bottom - rect.top, false); } // fill in the default contents of the window pData->windowKind = windowKind; pData->originalFileType = fileType; pData->pMakeWindow = (MakeWindowProc)thePreflight.makeProcPtr; pData->resRefNum = -1; pData->dataRefNum = -1; GetWindowPortBounds(pWindow, &pData->contentRect); // make the scroll bars { Rect controlRect; if (thePreflight.wantHScroll) { pData->contentRect.bottom -= kScrollBarSize; GetWindowPortBounds(pWindow, &controlRect); controlRect.top = controlRect.bottom - 16; if (thePreflight.wantVScroll) controlRect.right -= kGrowScrollAdjust; OffsetRect(&controlRect, -1, 1); CreateScrollBarControl(pWindow, &controlRect, 0, 0, 0, 0, true, gHActionProc, &pData->hScroll ); } if (thePreflight.wantVScroll) { pData->contentRect.right -= kScrollBarSize; GetWindowPortBounds(pWindow, &controlRect); controlRect.left = controlRect.right - 16; if (thePreflight.wantVScroll) controlRect.bottom -= kGrowScrollAdjust; OffsetRect(&controlRect, 1, -1); CreateScrollBarControl(pWindow, &controlRect, 0, 0, 0, 0, true, gVActionProc, &pData-> vScroll ); } } // got a name? Open the file if (fileSpec) { anErr = FSpOpenDF(fileSpec, thePreflight.openKind, &pData->dataRefNum); if ( ((anErr == afpAccessDenied) || (anErr == opWrErr) || (anErr == permErr) ) && (thePreflight.openKind != fsRdPerm) ) { thePreflight.openKind = fsRdPerm; pData->isWritable = false; anErr = FSpOpenDF(fileSpec, thePreflight.openKind, &pData->dataRefNum); } else pData->isWritable = true; nrequire(anErr, FailedToOpenFile); // okay not to find a resource fork, because some don't have them pData->resRefNum = FSpOpenResFile(fileSpec, thePreflight.openKind); // save the file spec in case someone is interested pData->fileSpec = *fileSpec; // alias for background file synchronization anErr = NewAlias( NULL, fileSpec, &pData->fileAlias ); nrequire(anErr, GoshNoAlias ); // // Most windows are not modifiable in SimpleText - only text files can be modified by SimpleText // if( gMachineInfo.haveProxyIcons ) { SetWindowModified( pWindow, false ); SetWindowProxyFSSpec( pWindow, fileSpec ); } } if (pData->pMakeWindow) { Rect oldContent = pData->contentRect; #ifdef __MWERKS__ #if __option(profile) ProfilerSetStatus(true); #endif #endif anErr = (*(pData->pMakeWindow)) (pWindow, pData); #ifdef __MWERKS__ #if __option(profile) ProfilerDump("\pmakewindow.prof"); ProfilerSetStatus(false); ProfilerClear(); #endif #endif if (!EqualRect(&oldContent, &pData->contentRect)) { SizeWindow(pWindow, pData->contentRect.right + (pData->vScroll != 0) * kScrollBarSize, pData->contentRect.bottom + (pData->hScroll != 0) * kScrollBarSize, false); } } nrequire(anErr, FailedMakeWindow); // got a name? Use it as the window title if ( (fileSpec) && (!pData->openAsNew) ) SetWTitle(pWindow, fileSpec->name); else { if ((gMachineInfo.documentCount == 1) && (pData->windowKind == kTextWindow)) { Str255 tempString; GetIndString(tempString, kMiscStrings, iFirstNewDocumentTitle); // get the "untitled" string (no number) SetWTitle(pWindow, tempString); } else { Str255 tempString; Str32 numString; GetWTitle(pWindow, tempString); NumToString(gMachineInfo.documentCount, numString); (void) ZeroStringSub(tempString, numString); SetWTitle(pWindow, tempString); } if (pData->bumpUntitledCount) gMachineInfo.documentCount++; // bump count if appropriate for this kind of document } // Make sure the scroll bars are reasonable in size, and move if they must AdjustScrollBars(pWindow, true, true, nil); // Show the scrollbars if( pData->hScroll != NULL ) ShowControl( pData->hScroll ); if( pData->vScroll != NULL ) ShowControl( pData->vScroll ); // finally, if all goes well, we can see the window itself! ShowWindow(pWindow); } return noErr; // EXCEPTION HANDLING FailedMakeWindow: DisposeHandle( (Handle)pData->fileAlias ); GoshNoAlias: if (pData->resRefNum != -1) CloseResFile(pData->resRefNum); if (pData->dataRefNum != -1) FSClose(pData->dataRefNum); FailedToOpenFile: DisposeWindow(pWindow); NewWindowFailed: DisposePtr((Ptr)pData); FailedToAllocateWindow: PreflightFailed: SanityCheckFailed: return anErr; } // MakeNewWindow // -------------------------------------------------------------------------------------------------------------- #pragma segment Main #define dontSaveChanges 3 #define kVisualDelay 8 static pascal Boolean SaveChangesFilter(DialogPtr theDialog, EventRecord *theEvent, short *itemHit) { if (StdFilterProc(theDialog, theEvent, itemHit)) return true; if (theEvent->what == updateEvt) { HandleEvent(theEvent); } if (theEvent->what == keyDown) { StringPtr keyEquivs = *GetString(kSaveChangesWindowID); unsigned char theKey = theEvent->message & charCodeMask; if (keyEquivs && (theKey == keyEquivs[1] || theKey == keyEquivs[2])) { short itemType; Rect theRect; ControlRef theControl; UInt32 finalTicks; GetDialogItem(theDialog, dontSaveChanges, &itemType, (Handle *) &theControl, &theRect); HiliteControl(theControl, kControlButtonPart); Delay(kVisualDelay, &finalTicks); HiliteControl(theControl, 0); *itemHit = dontSaveChanges; return true; } } return false; } static OSErr DoCloseWindow(WindowPtr pWindow, Boolean quitting, long keyTime) { OSErr anErr = noErr; WindowDataPtr pData = GetWindowInfo(pWindow); if ( (pData) && (pData->changed) ) { short hit; Str255 wTitle; DialogPtr dPtr; Cursor arrow; GetWTitle(pWindow, wTitle); SetCursor(GetQDGlobalsArrow(&arrow)); ParamText(wTitle, "\p", "\p", "\p"); if (gMachineInfo.haveNavigationServices) { hit = ConfirmSaveDialog(wTitle, quitting, MyEventProc); } else { hit = cancel; dPtr = GetNewDialog(kSaveChangesWindowID, nil, (WindowPtr)-1); if (dPtr) { SetDialogDefaultItem(dPtr, ok); SetDialogCancelItem (dPtr, cancel); BeginMovableModal(); do { MovableModalDialog(SaveChangesFilter, &hit); } while ((hit != dontSaveChanges) && (hit != ok) && (hit != cancel)); DisposeDialog(dPtr); EndMovableModal(); } } switch (hit) { case ok: anErr = DoCommand(pWindow, cSave, 0, 0); if (anErr == eUserCanceled) // redundant? gAllDone = false; break; case cancel: anErr = eUserCanceled; gAllDone = false; break; case dontSaveChanges: // don't save, so just close it break; } } if (anErr == noErr) { if ( (pData) && (pData->pCloseWindow) ) { // let the object close the window if it wishes to anErr = (*(pData->pCloseWindow)) (pWindow, pData); } // otherwise we close it the default way if (anErr == noErr) { if (pData) { DisposeWindow(pWindow); if (pData->hPageFormat) { DisposeHandle((Handle) pData->hPageFormat); pData->hPageFormat = nil; } if (pData->hPrintSettings) { DisposeHandle((Handle) pData->hPrintSettings); pData->hPrintSettings = nil; } if (pData->resRefNum != -1) CloseResFile(pData->resRefNum); if (pData->dataRefNum != -1) FSClose(pData->dataRefNum); DisposePtr((Ptr) pData); } } } // If we closed the last window, clean up if (FrontWindow() == nil) { UnhiliteMenuDelayed(keyTime); // unhilite before adjusting menus to avoid ugly menu title flashing AdjustMenus(nil, true, false); gMachineInfo.documentCount = 1; // back to "untitled" } // make sure we update the cursor SetEmptyRgn(gCursorRgn); return anErr; } // DoCloseWindow #undef dontSaveChanges // -------------------------------------------------------------------------------------------------------------- #pragma segment Main static OSErr DetermineWindowTypeOrOpen( FSSpecPtr theSpec, OSType theType, // optional input params -- file to open OSType *returnedTypeList, short * pNumTypes, // optional input params -- returns list of files Boolean *pWasAlreadyOpen) // optional input params -- was file already open { OSErr anErr = noErr; OSType typeList[20]; OSType docList[20]; short numTypes; // use local copies if the input params are nil if (returnedTypeList == nil) returnedTypeList = &typeList[0]; if (pNumTypes == nil) pNumTypes = &numTypes; *pNumTypes = 0; // Load up all of the file types we know how to handle AboutGetFileTypes(returnedTypeList, docList, pNumTypes); PICTGetFileTypes(returnedTypeList, docList, pNumTypes); #if ALLOW_QUICKTIME MovieGetFileTypes(returnedTypeList, docList, pNumTypes); #endif ClipboardGetFileTypes(returnedTypeList, docList, pNumTypes); TextGetFileTypes(returnedTypeList, docList, pNumTypes); #if ALLOW_QUICKTIME ThreeDGetFileTypes(returnedTypeList, docList, pNumTypes); #endif if (theSpec != nil) { short index; OSType windowType = '????'; for (index = 0; index < (*pNumTypes); ++index) if (theType == returnedTypeList[index]) windowType = docList[index]; #if ALLOW_QUICKTIME if (windowType == '????' && gMachineInfo.haveQuickTime) { ComponentDescription ci; ci.componentType = GraphicsImporterComponentType; ci.componentSubType = theType; ci.componentManufacturer = kAnyComponentManufacturer; ci.componentFlags = 0; ci.componentFlagsMask = movieImportSubTypeIsFileExtension; if( 0 != FindNextComponent( 0, &ci ) ) { windowType = 'PICT'; } } #endif if (windowType != '????') { if ( (theType == 'TEXT') || (theType == 'sEXT') ) { FInfo theInfo; FSpGetFInfo(theSpec, &theInfo); if ((theInfo.fdFlags & kIsStationery) != 0) theType = 'sEXT'; else theType = 'TEXT'; } anErr = MakeNewWindow(windowType, theSpec, theType, pWasAlreadyOpen); } else anErr = eDocumentWrongKind; } return anErr; } // DetermineWindowTypeOrOpen // -------------------------------------------------------------------------------------------------------------- #pragma segment Main #if 0 // Handle update/activate events behind Standard File static pascal Boolean OpenDialogFilter(DialogPtr theDialog, EventRecord *theEvent, short *itemHit, void *myDataPtr) { #pragma unused(myDataPtr) // Pass updates through (Activates are tricky...was mucking with Apple menu & thereby // drastically changing how the system handles the menu bar during our alert) if ( (theEvent->what == updateEvt) && (theEvent->message != (long)theDialog) ) HandleEvent(theEvent); if (StdFilterProc(theDialog, theEvent, itemHit)) return(true); return(false); } // OpenDialogFilter #endif #if 0 #if GENERATINGCFM static RoutineDescriptor gOpenDialogFilterRD = BUILD_ROUTINE_DESCRIPTOR(uppModalFilterYDProcInfo, OpenDialogFilter); static ModalFilterYDUPP gOpenDialogFilter = &gOpenDialogFilterRD; #else static ModalFilterYDUPP gOpenDialogFilter = NewModalFilterYDProc(OpenDialogFilter); #endif #endif static OSErr DoOpenWindow(void) { OSErr anErr = noErr; short numTypes; OSType typeList[20]; // Point thePoint = { -1, -1 }; FSSpec fileSpec; OSType fileType = '????'; Boolean fileSelected = false; DetermineWindowTypeOrOpen(nil, fileType, &typeList[0], &numTypes, nil); if (gMachineInfo.haveNavigationServices) { #if qSingleSelectionOnly fileSelected = OpenFileDialog('ttxt', numTypes, typeList, MyEventProc, &fileSpec, &fileType) == noErr; #else // Open as many documents as the user wishes thruogh Appleevents OpenFileDialog('ttxt', numTypes, typeList, MyEventProc, NULL, NULL); fileSelected = false; #endif } else { #if(0) StandardFileReply sfReply; if (gMachineInfo.haveQuickTime) { CustomGetFilePreview(nil, numTypes, typeList, &sfReply, 0, thePoint, nil, gOpenDialogFilter, nil, nil, nil); } else { CustomGetFile(nil, numTypes, typeList, &sfReply, 0, thePoint, nil, gOpenDialogFilter, nil, nil, nil); } fileSelected= sfReply.sfGood; fileSpec = sfReply.sfFile; fileType = sfReply.sfType; #endif } if (fileSelected) { Cursor arrow; SetWatchCursor(); anErr = DetermineWindowTypeOrOpen(&fileSpec, fileType, &typeList[0], &numTypes, nil); SetCursor(GetQDGlobalsArrow(&arrow)); } return anErr; } // DoOpenWindow // -------------------------------------------------------------------------------------------------------------- #pragma segment Main static OSErr DoUpdateWindow(WindowPtr pWindow) { OSErr anErr = noErr; WindowDataPtr pData = GetWindowInfo(pWindow); GrafPtr curPort; // only handle updates for windows we know about if (pData) { GetPort(&curPort); SetPort((GrafPtr)GetWindowPort(pWindow)); BeginUpdate(pWindow); if (pData->pUpdateWindow) anErr = (*(pData->pUpdateWindow)) (pWindow, pData); EndUpdate(pWindow); SetPort(curPort); } return anErr; } // DoUpdateWindow // -------------------------------------------------------------------------------------------------------------- #pragma segment Main OSErr DoScrollContent(WindowPtr pWindow, WindowDataPtr pData, short deltaH, short deltaV) { OSErr anErr = noErr; if ((deltaH) || (deltaV)) { if ((pData) && (pData->pScrollContent)) anErr = (*(pData->pScrollContent)) (pWindow, pData, deltaH, deltaV); if (anErr == noErr) { RgnHandle invalidRgn = NewRgn(); ScrollRect(&pData->contentRect, deltaH, deltaV, invalidRgn); InvalWindowRgn(pWindow,invalidRgn); DisposeRgn(invalidRgn); DoUpdateWindow(pWindow); } } return anErr; } // DoScrollContent // -------------------------------------------------------------------------------------------------------------- #pragma segment Main static OSErr DoContentClick(WindowPtr pWindow) { OSErr anErr = noErr; WindowDataPtr pData = GetWindowInfo(pWindow); if ( pData ) { SetPort((GrafPtr) GetWindowPort(pWindow)); if (pData->pContentClick) { // let the object handle the click if it wishes to anErr = (*(pData->pContentClick)) (pWindow, pData, &gEvent); // invalidate the cursor rgn in case the object changed its appearance if (anErr != noErr) SetEmptyRgn(gCursorRgn); } if (anErr == noErr) { ControlHandle theControl; short part; GlobalToLocal(&gEvent.where); part = FindControl(gEvent.where, pWindow, &theControl); switch (part) { // do nothing for viewRect case case 0: break; // track the thumb, and then update all at once case kControlIndicatorPart: { short value = GetControlValue(theControl); if (gMachineInfo.haveAppearanceMgr) { if (theControl == pData->hScroll) { pData->oldHValue = GetControlValue(theControl); part = TrackControl(theControl, gEvent.where, gHActionProc); } if (theControl == pData->vScroll) { pData->oldVValue = GetControlValue(theControl); part = TrackControl(theControl, gEvent.where, gVActionProc); } } else { part = TrackControl(theControl, gEvent.where, nil); if (part != 0) { // turn the value into a delta value -= GetControlValue(theControl); // if we actually moved if (value != 0) { if (theControl == pData->hScroll) DoScrollContent(pWindow, pData, value, 0); if (theControl == pData->vScroll) DoScrollContent(pWindow, pData, 0, value); } } } } break; // track the control, and scroll as we go default: if (theControl) { if (theControl == pData->hScroll) part = TrackControl(theControl, gEvent.where, gHActionProc); if (theControl == pData->vScroll) part = TrackControl(theControl, gEvent.where, gVActionProc); } break; } } } return anErr; } // DoContentClick // -------------------------------------------------------------------------------------------------------------- #pragma segment Main static OSErr DoGrowWindow(WindowPtr pWindow, EventRecord *pEvent) { OSErr anErr = noErr; WindowDataPtr pData = GetWindowInfo(pWindow); Rect tempRect; LongRect docRect; long growResult; if (pData) { GrafPtr pPort = (GrafPtr)GetWindowPort(pWindow); SetPort(pPort); RectToLongRect(&pData->contentRect, &docRect); if (pData->pGetDocumentRect) (*(pData->pGetDocumentRect)) (pWindow, pData, &docRect, true); if (pData->vScroll) docRect.right += 16; if (pData->hScroll) docRect.bottom += 16; if ( (pData->hasGrow) && (pData->hScroll == nil) && (pData->vScroll == nil) ) { docRect.right += 16; docRect.bottom += 16; } // set up resize constraints tempRect.left = pData->minHSize; if (tempRect.left == 0) tempRect.left = kMinDocSize; tempRect.right = docRect.right - docRect.left; if (tempRect.right < tempRect.left) tempRect.right = tempRect.left; tempRect.top = pData->minVSize; if (tempRect.top == 0) tempRect.top = kMinDocSize; tempRect.bottom = docRect.bottom - docRect.top; if (tempRect.bottom < tempRect.top) tempRect.bottom = tempRect.top; growResult = GrowWindow(pWindow, pEvent->where, &tempRect); if ( growResult != 0 ) { Rect oldRect; Boolean needInvalidate; // save old content area oldRect = pData->contentRect; // grow window and recalc what is needed SizeWindow(pWindow, growResult & 0xFFFF, growResult >> 16, true); GetWindowPortBounds(pWindow, &pData->contentRect); AdjustScrollBars(pWindow, true, true, &needInvalidate); if (needInvalidate) { InvalWindowRect(pWindow, &pData->contentRect); } // if we have offset scrollbars, then force a redraw of them if (pData->hScrollOffset) { GetWindowPortBounds(pWindow, &oldRect); oldRect.right = oldRect.left + pData->hScrollOffset; oldRect.top = oldRect.bottom - kScrollBarSize; InvalWindowRect(pWindow,&oldRect); } if (pData->vScrollOffset) { GetWindowPortBounds(pWindow, &oldRect); oldRect.bottom = oldRect.top + pData->vScrollOffset; oldRect.left = oldRect.right - kScrollBarSize; InvalWindowRect(pWindow,&oldRect); } } } return anErr; } // DoGrowWindow // -------------------------------------------------------------------------------------------------------------- #pragma segment Main static OSErr DoZoomWindow(WindowPtr pWindow, short zoomDir) { Rect windRect, zoomRect; Rect globalPortRect, theSect, dGDRect; GDHandle nthDevice, dominantGDevice; long sectArea, greatestArea; short hMax, vMax; Rect bounds; // determine the max size of the window { WindowDataPtr pData = GetWindowInfo(pWindow); LongRect docRect; RectToLongRect(&pData->contentRect, &docRect); if (pData->pGetDocumentRect) (*(pData->pGetDocumentRect)) (pWindow, pData, &docRect, true); if (pData->vScroll) docRect.right += kScrollBarSize; if (pData->hScroll) docRect.bottom += kScrollBarSize; if ( (pData->hasGrow) && (pData->hScroll == nil) && (pData->vScroll == nil) ) { docRect.right += kScrollBarSize; docRect.bottom += kScrollBarSize; } hMax = docRect.right - docRect.left; vMax = docRect.bottom - docRect.top; } SetPort((GrafPtr) GetWindowPort(pWindow)); GetWindowPortBounds(pWindow, &bounds); EraseRect(&bounds); // recommended for cosmetic reasons if (zoomDir == inZoomOut) { /* * ZoomWindow() is a good basic tool, but it doesn't do everything necessary to * implement a good human interface when zooming. In fact it's not even close for * more high-end hardware configurations. We must help it along by calculating an * appropriate window size and location any time a window zooms out. */ { RgnHandle structRgn = NewRgn(); GetWindowRegion(pWindow, kWindowStructureRgn, structRgn); GetRegionBounds( structRgn, &windRect); DisposeRgn(structRgn); } dominantGDevice = nil; /* * Color QuickDraw implies the possibility of multiple monitors. This is where * zooming becomes more interesting. One should zoom onto the monitor containing * the greatest portion of the window. This requires walking the gDevice list. */ nthDevice = GetDeviceList(); greatestArea = 0; while (nthDevice != nil) { if (TestDeviceAttribute(nthDevice, screenDevice)) { if (TestDeviceAttribute(nthDevice, screenActive)) { SectRect(&windRect, &(**nthDevice).gdRect, &theSect); sectArea = (long) RectWidth(theSect) * (long) RectHeight(theSect); if (sectArea > greatestArea) { greatestArea = sectArea; // save the greatest intersection dominantGDevice = nthDevice; // and which device it belongs to } } } nthDevice = GetNextDevice(nthDevice); } /* * At this point, we know the dimensions of the window we're zooming, and we know * what screen we're going to put it on. To be more specific, however, we need a * rectangle which defines the maximum dimensions of the resized window's contents. * This rectangle accounts for the thickness of the window frame, the menu bar, and * one or two pixels around the edges for cosmetic compatibility with ZoomWindow(). */ if (dominantGDevice != nil) { dGDRect = (**dominantGDevice).gdRect; if (dominantGDevice == GetMainDevice()) // account for menu bar on main device dGDRect.top += GetMBarHeight(); } else { BitMap bitmap; GetQDGlobalsScreenBits(&bitmap); dGDRect = bitmap.bounds ; // if no gDevice, use default monitor dGDRect.top += GetMBarHeight(); } GetWindowPortBounds(pWindow, &globalPortRect); LocalToGlobal(&TopLeft(globalPortRect)); // calculate the window's portRect LocalToGlobal(&BotRight(globalPortRect)); // in global coordinates // account for the window frame and inset it a few pixels dGDRect.left += 2 + globalPortRect.left - windRect.left; dGDRect.top += 2 + globalPortRect.top - windRect.top; dGDRect.right -= 1 + windRect.right - globalPortRect.right; dGDRect.bottom -= 1 + windRect.bottom - globalPortRect.bottom; /* * Now we know exactly what our limits are, and since there are input parameters * specifying the dimensions we'd like to see, we can move and resize the zoom * state rectangle for the best possible results. We have three goals in this: * 1. Display the window entirely visible on a single device. * 2. Resize the window to best represent the dimensions of the document itself. * 3. Move the window as short a distance as possible to achieve #1 and #2. */ //zoomRect = &(**(WStateDataHandle) ((WindowPeek) pWindow)->dataHandle).stdState; GetWindowIdealUserState(pWindow, &zoomRect); /* * Initially set the zoom rectangle to the size requested by the input parameters, * although not smaller than a minimum size. We do this without moving the origin. */ zoomRect.right = (zoomRect.left = globalPortRect.left) + Max(hMax, kMinDocSize); zoomRect.bottom = (zoomRect.top = globalPortRect.top) + Max(vMax, kMinDocSize); // Shift the entire rectangle if necessary to bring its origin inside dGDRect. OffsetRect(&zoomRect, Max(dGDRect.left - zoomRect.left, 0), Max(dGDRect.top - zoomRect.top, 0)); /* * Shift the rectangle up and/or to the left if necessary to accomodate the view, * and if it is possible to do so. The rectangle may not be moved such that its * origin would fall outside of dGDRect. */ OffsetRect(&zoomRect, -Pin(zoomRect.right - dGDRect.right, 0, zoomRect.left - dGDRect.left), -Pin(zoomRect.bottom - dGDRect.bottom, 0, zoomRect.top - dGDRect.top)); // Clip expansion to dGDRect, in case view is larger than dGDRect. zoomRect.right = Min(zoomRect.right, dGDRect.right); zoomRect.bottom = Min(zoomRect.bottom, dGDRect.bottom); SetWindowIdealUserState(pWindow, &zoomRect); } ZoomWindow(pWindow, zoomDir, pWindow == FrontWindow()); AdjustScrollBars(pWindow, true, true, nil); GetWindowPortBounds(pWindow, &bounds); InvalWindowRect(pWindow,&bounds); return noErr; } // DoZoomWindow // -------------------------------------------------------------------------------------------------------------- #pragma segment Main OSErr DoActivate(WindowPtr pWindow, Boolean activating) { OSErr anErr = noErr; WindowDataPtr pData = GetWindowInfo(pWindow); SetPort((GrafPtr) GetWindowPort(pWindow)); if ( pData ) { if (pData->pActivateEvent) anErr = (*(pData->pActivateEvent)) (pWindow, pData, activating); if (anErr == noErr) { if (activating) { if (pData->hScroll) HiliteControl( pData->hScroll, 0 ); if (pData->vScroll) HiliteControl( pData->vScroll, 0 ); } else { if (pData->hScroll) HiliteControl( pData->hScroll, kControlDisabledPart ); if (pData->vScroll) HiliteControl( pData->vScroll, kControlDisabledPart ); } if ( pData->hasGrow ) { Rect growIconRect; CalculateGrowIcon(pWindow,pData, &growIconRect); InvalWindowRect(pWindow,&growIconRect); } } } AdjustMenus(pWindow, true, false); return anErr; } // DoActivate // -------------------------------------------------------------------------------------------------------------- #pragma segment Main // -------------------------------------------------------------------------------------------------------------- #pragma segment Main OSErr DoDefault(WindowDataPtr pData) { OSErr anErr = noErr; OSStatus status; status = PMBegin(); // create default page format if ((status == noErr) && (pData->hPageFormat == nil)) { PMPageFormat pageFormat = kPMNoPageFormat; status = PMNewPageFormat(&pageFormat); if ((status == noErr) && (pageFormat != kPMNoPageFormat)) status = PMDefaultPageFormat(pageFormat); if (status == noErr) status = PMFlattenPageFormat(pageFormat, &pData->hPageFormat); if (pageFormat != kPMNoPageFormat) (void)PMDisposePageFormat(pageFormat); } // create default print settings if ((status == noErr) && (pData->hPrintSettings == nil)) { PMPrintSettings printSettings = kPMNoPrintSettings; status = PMNewPrintSettings(&printSettings); if ((status == noErr) && (printSettings != kPMNoPrintSettings)) status = PMDefaultPrintSettings(printSettings); if (status == noErr) status = PMFlattenPrintSettings(printSettings, &pData->hPrintSettings); if (printSettings != kPMNoPrintSettings) (void)PMDisposePrintSettings(printSettings); } (void)PMEnd(); anErr = (OSErr)status; return anErr; } // -------------------------------------------------------------------------------------------------------------- #pragma segment Printing OSErr DoPageSetup(WindowPtr pWindow) { OSErr anErr = noErr; WindowDataPtr pData = GetWindowInfo(pWindow); Boolean accepted; anErr = DoDefault(pData); nrequire(anErr, DoDefault); if (pData->hPageFormat != nil) { OSStatus status; status = PMBegin(); if (status == noErr) { PMPageFormat pageFormat = kPMNoPageFormat; // retrieve the default page format status = PMUnFlattenPageFormat(pData->hPageFormat, &pageFormat); if ((status == noErr) && (pageFormat != kPMNoPageFormat)) { Cursor arrow; SetCursor(GetQDGlobalsArrow(&arrow)); status = PMPageSetUpDialog(pageFormat, &accepted); if (!accepted) status = kPMCancel; } // save any changes to the page format if (status == noErr && accepted) { DisposeHandle( pData->hPageFormat ); pData->hPageFormat = nil; status = PMFlattenPageFormat(pageFormat, &pData->hPageFormat); } if (pageFormat != kPMNoPageFormat) (void)PMDisposePageFormat(pageFormat); } (void)PMEnd(); anErr = (OSErr)status; } // FALL THROUGH EXCEPTION HANDLING DoDefault: return anErr; } // DoPageSetup // -------------------------------------------------------------------------------------------------------------- #pragma segment Printing static OSErr DoPrintSetup(WindowPtr pWindow, StringPtr pPrinterName) { #pragma unused (pPrinterName) OSErr anErr = noErr; WindowDataPtr pData = GetWindowInfo(pWindow); Boolean accepted; anErr = DoDefault(pData); nrequire(anErr, DoDefault); if ((pData->hPrintSettings != nil) && (pData->hPageFormat != nil)) { OSStatus status; status = PMBegin(); if (status == noErr) { PMPrintSettings printSettings = kPMNoPrintSettings; PMPageFormat pageFormat = kPMNoPageFormat; // retrieve the default printing objects status = PMUnFlattenPageFormat(pData->hPageFormat, &pageFormat); if (status == noErr) status = PMUnFlattenPrintSettings(pData->hPrintSettings, &printSettings); if ((status == noErr) && (printSettings != kPMNoPrintSettings) && (pageFormat != kPMNoPageFormat)) { Cursor arrow; SetCursor(GetQDGlobalsArrow(&arrow)); status = PMPrintDialog(printSettings, pageFormat, &accepted ); if (!accepted) status = eUserCanceled; } if (status == noErr && accepted) { // replace with the new print settings handle // NOTE: the pageFormat object does not get modified DisposeHandle(pData->hPrintSettings); pData->hPrintSettings = nil; status = PMFlattenPrintSettings(printSettings, &pData->hPrintSettings); } if (printSettings != kPMNoPrintSettings) (void)PMDisposePrintSettings(printSettings); } (void)PMEnd(); anErr = (OSErr)status; } // FALL THROUGH EXCEPTION HANDLING DoDefault: return anErr; } // DoPrintSetup // -------------------------------------------------------------------------------------------------------------- #pragma segment Printing static OSErr DoPrint(WindowPtr pWindow, void * hPageFormat, void * hPrintSettings, Boolean oneCopy) { WindowDataPtr pData = GetWindowInfo(pWindow); Boolean didAllocate = false; OSStatus status; PMPageFormat pageFormat = kPMNoPageFormat; PMPrintSettings printSettings = kPMNoPrintSettings; PMPrintContext thePrintingPort = kPMNoReference; status = PMBegin(); if (status == noErr) { if (hPageFormat != nil) { status = PMUnFlattenPageFormat(hPageFormat, &pageFormat); } else { status = PMNewPageFormat(&pageFormat); if ((status == noErr) && (pageFormat != kPMNoPageFormat)) status = PMDefaultPageFormat(pageFormat); } if (hPrintSettings != nil) { status = PMUnFlattenPrintSettings(hPrintSettings, &printSettings); } else { status = PMNewPrintSettings(&printSettings); if ((status == noErr) && (printSettings != kPMNoPrintSettings)) status = PMDefaultPrintSettings(printSettings); } } if (status == noErr) { long pageIndex; UInt32 firstPage, lastPage; // be sure to get the page range BEFORE calling PrValidate(), // which blows it away for many drivers. status = PMGetFirstPage(printSettings, &firstPage); if (status == noErr) status = PMGetLastPage(printSettings, &lastPage); if (status == noErr) status = PMValidatePrintSettings(printSettings, kPMDontWantBoolean); status = PMGetFirstPage(printSettings, &firstPage); if (status == noErr) status = PMGetLastPage(printSettings, &lastPage); if (status == noErr) status = PMSetFirstPage(printSettings, 1, true); if (status == noErr) status = PMSetLastPage(printSettings, 9999, true); if ((status == noErr) && (oneCopy)) status = PMSetCopies(printSettings, 1, true); if (status == noErr) { Rect pageRect; status = PMBeginDocument(printSettings, pageFormat, &thePrintingPort); if ((status == noErr) && (thePrintingPort != kPMNoReference)) { PMRect tempPageRect; status = PMGetAdjustedPageRect(pageFormat, &tempPageRect); if (status == noErr) { pageRect.top = tempPageRect.top; pageRect.left = tempPageRect.left; pageRect.bottom = tempPageRect.bottom; pageRect.right = tempPageRect.right; if (firstPage < 1) firstPage = 1; if (lastPage < firstPage) lastPage = firstPage; for (pageIndex = firstPage; pageIndex <= lastPage; ++pageIndex) { status = PMBeginPage(thePrintingPort, nil); if (status == noErr) status = (OSStatus)(*(pData->pPrintPage)) (pWindow, pData, &pageRect, &pageIndex); status = PMEndPage(thePrintingPort); if ((status != noErr) || (pageIndex == -1)) break; } } (void)PMEndDocument(thePrintingPort); } } } if (printSettings != kPMNoPrintSettings) (void)PMDisposePrintSettings(printSettings); if (pageFormat != kPMNoPageFormat) (void)PMDisposePageFormat(pageFormat); (void)PMEnd(); return (OSErr)status; } // DoPrint // -------------------------------------------------------------------------------------------------------------- #pragma segment Main OSErr DoCommand(WindowPtr pWindow, short commandID, long menuResult, long keyTime) { OSErr anErr = noErr; WindowDataPtr pData = nil; if (pWindow) { pData = (WindowDataPtr) GetWindowInfo(pWindow); if ( (pData) && (pData->pCommand) ) anErr = (*(pData->pCommand)) (pWindow, pData, commandID, menuResult); } if (anErr == noErr) { // default command handling switch (commandID) { // About box command case cAbout: if (!BringToFrontIfExists(kAboutWindow)) anErr = MakeNewWindow(kAboutWindow, nil, '????', nil); break; #if(0) case cDeskAccessory: { Str255 tempString; GetMenuItemText(GetMenuHandle(menuResult>>16), menuResult & 0xFFFF, tempString); OpenDeskAcc(tempString); } break; #endif // New window command case cNew: anErr = MakeNewWindow(kTextWindow, nil, 'TEXT', nil); break; // Open window command case cOpen: anErr = DoOpenWindow(); break; // Close window command case cClose: anErr = DoCloseWindow(pWindow, false, keyTime); break; case cPageSetup: anErr = DoPageSetup(pWindow); break; case cPrint: anErr = DoPrintSetup(pWindow, nil); if (anErr == noErr) anErr = DoPrint(pWindow, pData->hPageFormat, pData->hPrintSettings, false); break; case cPrintOneCopy: anErr = DoPrint(pWindow, pData->hPageFormat, pData->hPrintSettings, true); break; // get out of here command! case cQuit: gAllDone = true; break; // show/hide clipboard case cShowClipboard: if (!BringToFrontIfExists(kClipboardWindow)) { anErr = MakeNewWindow(kClipboardWindow, nil, '????', nil); } else { pWindow = FrontWindow(); anErr = DoCloseWindow(pWindow, false, keyTime); } break; case cNextPage: gEvent.what = keyDown; gEvent.message = kPageDown << 8; gEvent.modifiers = 0; DoKeyEvent(pWindow, &gEvent, false); break; case cPreviousPage: gEvent.what = keyDown; gEvent.message = kPageUp << 8; gEvent.modifiers = 0; DoKeyEvent(pWindow, &gEvent, false); break; // Do nothing command case cNull: break; default: break; } } // don't report cancels if (anErr == kPMCancel) anErr = noErr; if ( (anErr != noErr) && (anErr != eActionAlreadyHandled) && (anErr != eUserCanceled) ) { // some commands are so similar to other commands that we map their IDs // for the purposes of the error strings if (commandID == cSaveAs) commandID = cSave; if (commandID == cPrintOneCopy) commandID = cPrint; ConductErrorDialog(anErr, commandID, cancel); } // in any case, unhilite the menu selected after command processing is done, // but first delay for a short while if the command was invoked via a cmd key // so that the menu title is hilighted long enough for the user to see it UnhiliteMenuDelayed(keyTime); return anErr; } // DoCommand // -------------------------------------------------------------------------------------------------------------- #pragma segment Main static OSErr DoMenuCommand(WindowPtr pWindow, long menuResult, long keyTime) { OSErr anErr = noErr; short commandID = cNull; short ** commandHandle; short menuID = menuResult >> 16; if (menuID >= mFontSubMenusStart) { commandID = cSelectFontStyle; } else { // read in the resource that controls this menu { short oldResFile = CurResFile(); UseResFile(gApplicationResFile); commandHandle = (short**) Get1Resource('MCMD', menuID); UseResFile(oldResFile); anErr = ResError(); nrequire(anErr, FailedToLoadCommandTable); } if (commandHandle) { short item = menuResult & 0xFFFF; short * pCommands = *commandHandle; if (item <= pCommands[0]) commandID = pCommands[item]; else commandID = pCommands[pCommands[0]]; } } anErr = DoCommand(pWindow, commandID, menuResult, keyTime); // FALL THROUGH EXCEPTION HANDLING FailedToLoadCommandTable: return anErr; } // DoMenuCommand // -------------------------------------------------------------------------------------------------------------- #pragma segment Main static void DoKeyPageDown(WindowPtr pWindow, WindowDataPtr pData, Boolean processPageControls) { if (GetControlValue(pData->vScroll) < GetControlMaximum(pData->vScroll)) VActionProc(pData->vScroll, kControlPageDownPart); else { if ( (processPageControls) && (IsCommandEnabled(cNextPage)) ) { short amount; if (DoCommand(pWindow, cNextPage, 0, 0) == eActionAlreadyHandled) { amount = GetControlValue(pData->vScroll); SetControlAndClipAmount(pData->vScroll, &amount); if (amount != 0) DoScrollContent(pWindow, pData, 0, amount); } AdjustMenus(pWindow, true, false); } } } // DoKeyPageDown // -------------------------------------------------------------------------------------------------------------- #pragma segment Main static void DoKeyPageUp(WindowPtr pWindow, WindowDataPtr pData, Boolean processPageControls) { if (GetControlValue(pData->vScroll) > GetControlMinimum(pData->vScroll)) VActionProc(pData->vScroll, kControlPageUpPart); else { if ( (processPageControls) && (IsCommandEnabled(cPreviousPage)) ) { short amount; if (DoCommand(pWindow, cPreviousPage, 0, 0) == eActionAlreadyHandled) { amount = -(GetControlMaximum(pData->vScroll)-GetControlValue(pData->vScroll)); SetControlAndClipAmount(pData->vScroll, &amount); if (amount != 0) DoScrollContent(pWindow, pData, 0, amount); } AdjustMenus(pWindow, true, false); } } } // DoKeyPageUp // -------------------------------------------------------------------------------------------------------------- #pragma segment Main OSErr DoKeyEvent(WindowPtr pWindow, EventRecord * pEvent, Boolean processPageControls) { OSErr anErr = noErr; WindowDataPtr pData = nil; Boolean passToObject = false; Boolean isMotionKey = false; long menuResult = 0; char keyCode = (pEvent->message >> 8) & charCodeMask; if (pWindow) pData = GetWindowInfo(pWindow); if ( pEvent->modifiers & cmdKey ) /* Command key down */ { if ( (pData) && (pData->pPreMenuAccess) ) (void) (*(pData->pPreMenuAccess)) (pWindow, pData); AdjustMenus(pWindow, true, false); menuResult = MenuKey(pEvent->message & charCodeMask); DoMenuCommand(pWindow, menuResult, TickCount()); pWindow = FrontWindow(); } if (menuResult == 0) { if (pWindow) { if ( (pData) && (pData->pKeyEvent) ) passToObject = true; SetPort((GrafPtr) GetWindowPort(pWindow)); } if (pData) { switch (keyCode) { case kHome: // top of file isMotionKey = true; if (pData->vScroll) { short amount; if ( (processPageControls) && (IsCommandEnabled(cGotoPage)) ) DoCommand(pWindow, cGotoPage, cGotoFirst, 0); amount = GetControlValue(pData->vScroll); SetControlAndClipAmount(pData->vScroll, &amount); if (amount != 0) DoScrollContent(pWindow, pData, 0, amount); passToObject = false; } break; case kEnd: // end of file isMotionKey = true; if (pData->vScroll) { short amount; if ( (processPageControls) && (IsCommandEnabled(cGotoPage)) ) DoCommand(pWindow, cGotoPage, cGotoLast, 0); amount = -(GetControlMaximum(pData->vScroll)-GetControlValue(pData->vScroll)); SetControlAndClipAmount(pData->vScroll, &amount); if (amount != 0) DoScrollContent(pWindow, pData, 0, amount); passToObject = false; } break; case kPageUp: // scroll bar page up isMotionKey = true; if (pData->vScroll) { DoKeyPageUp(pWindow, pData, processPageControls); passToObject = false; } break; case kPageDown: // scroll bar page down isMotionKey = true; if (pData->vScroll) { DoKeyPageDown(pWindow, pData, processPageControls); passToObject = false; } break; case kUpArrow: // scroll bar up arrow isMotionKey = true; if ( (pData->vScroll) && (!pData->pKeyEvent) ) { if ( pEvent->modifiers & cmdKey ) /* Command key down */ DoKeyPageUp(pWindow, pData, processPageControls); else VActionProc(pData->vScroll, kControlUpButtonPart); passToObject = false; } break; case kDownArrow: // scroll bar down arrow isMotionKey = true; if ( (pData->vScroll) && (!pData->pKeyEvent) ) { if ( pEvent->modifiers & cmdKey ) /* Command key down */ DoKeyPageDown(pWindow, pData, processPageControls); else VActionProc(pData->vScroll, kControlDownButtonPart); passToObject = false; } break; case kLeftArrow: // scroll bar left arrow isMotionKey = true; if ( (pData->hScroll) && (!pData->pKeyEvent) ) { if ( pEvent->modifiers & cmdKey ) /* Command key down */ HActionProc(pData->hScroll, kControlPageUpPart); else HActionProc(pData->hScroll, kControlUpButtonPart); passToObject = false; } break; case kRightArrow: // scroll bar right arrow isMotionKey = true; if ( (pData->hScroll) && (!pData->pKeyEvent) ) { if ( pEvent->modifiers & cmdKey ) /* Command key down */ HActionProc(pData->hScroll, kControlPageDownPart); else HActionProc(pData->hScroll, kControlDownButtonPart); passToObject = false; } break; } if (passToObject) anErr = (*(pData->pKeyEvent)) (pWindow, pData, pEvent, isMotionKey); else { if ( (pData->documentAcceptsText == false) && !( pEvent->modifiers & cmdKey ) && !(isMotionKey) ) anErr = eDocumentNotModifiable; } } if ( (anErr != noErr) && (anErr != eActionAlreadyHandled) ) ConductErrorDialog(anErr, cTypingCommand, ok); } // (menuResult == 0) return anErr; } // DoKeyEvent // -------------------------------------------------------------------------------------------------------------- #pragma segment Main OSErr DoAdjustCursor(WindowPtr pWindow, Point *where) { OSErr anErr = noErr; Point whereMouse; Boolean didAdjust = false; if (where) whereMouse = *where; if (pWindow) { // not one of our windows? don't do anything if (GetWindowKind(pWindow) != userKind) didAdjust = true; SetPort((GrafPtr) GetWindowPort(pWindow)); if ( (!didAdjust) && (gMachineInfo.haveTSM) ) { if (!where) { GetMouse(&whereMouse); LocalToGlobal(&whereMouse); } if (SetTSMCursor(whereMouse)) didAdjust = true; } if (!didAdjust) { WindowDataPtr pData = GetWindowInfo(pWindow); RgnHandle content = NewRgn(); Point globalMouse; SetEmptyRgn(gCursorRgn); if (!where) GetMouse(&whereMouse); globalMouse = whereMouse; LocalToGlobal(&globalMouse); GetWindowRegion(pWindow, kWindowContentRgn, content); if ((pData) && (PtInRgn(globalMouse, content)) && (PtInRect(whereMouse, &pData->contentRect))) { Rect tempRect; tempRect = pData->contentRect; LocalToGlobal(&TopLeft(tempRect)); LocalToGlobal(&BotRight(tempRect)); RectRgn(gCursorRgn, &tempRect); if (pData->pAdjustCursor) anErr = (*(pData->pAdjustCursor)) (pWindow, pData, &whereMouse, gCursorRgn); } DisposeRgn(content); } else anErr = eActionAlreadyHandled; } // nobody set the cursor, we do it ourselves if (anErr != eActionAlreadyHandled) { Cursor arrow; SetCursor(GetQDGlobalsArrow(&arrow)); } return anErr; } // DoAdjustCursor // -------------------------------------------------------------------------------------------------------------- #pragma segment Main static long DetermineWaitTime(WindowPtr pWindow) { long waitTime = kMaxWaitTime; while (pWindow) { long newWaitTime; WindowDataPtr pData = GetWindowInfo(pWindow); if ((pData) && (pData->pCalculateIdleTime)) newWaitTime = (*(pData->pCalculateIdleTime)) (pWindow, pData); else newWaitTime = kMaxWaitTime; if (newWaitTime < waitTime) waitTime = newWaitTime; pWindow = GetNextWindow(pWindow); } return(waitTime); } // DetermineWaitTime // -------------------------------------------------------------------------------------------------------------- #pragma segment Main static OSStatus GetFinderProcess( ProcessSerialNumber * outPSN ) { ProcessInfoRec processInfo; OSErr outStatus = noErr; outPSN->lowLongOfPSN = 0; outPSN->highLongOfPSN = kNoProcess; processInfo.processInfoLength = sizeof(ProcessInfoRec); processInfo.processName = nil; processInfo.processAppSpec = nil; while( outStatus == noErr ) { outStatus = GetNextProcess( outPSN ); if( outStatus == noErr ) { outStatus = GetProcessInformation( outPSN, &processInfo ); if( (outStatus == noErr) && (processInfo.processSignature == 'MACS') && (processInfo.processType == 'FNDR') ) { break; } } } return outStatus; } static OSStatus BringFinderToFront(void) { OSStatus outStatus; ProcessSerialNumber finderProcess; outStatus = GetFinderProcess( &finderProcess ); if ( outStatus == noErr ) { outStatus = SetFrontProcess( &finderProcess ); } return outStatus; } void HandleEvent(EventRecord * pEvent) { WindowPtr pWindow; Boolean handled; pWindow = FrontWindow(); handled = false; switch (pEvent->what) { case kHighLevelEvent: AEProcessAppleEvent(pEvent); break; case osEvt: switch ((pEvent->message >> 24) & 0xFF) /* high byte of message */ { case mouseMovedMessage: DoAdjustCursor(pWindow, nil); break; case suspendResumeMessage: /* suspend/resume is also an activate/deactivate */ gMachineInfo.amInBackground = (pEvent->message & 1) == 0; if (pWindow) DoActivate(pWindow, !gMachineInfo.amInBackground); break; } break; case activateEvt: pWindow = (WindowPtr) pEvent->message; DoActivate(pWindow, (pEvent->modifiers & activeFlag) != 0); break; // disk inserted events must be handled, or uninitialized floppies // won't be recognized. case diskEvt: if ( HiWord(pEvent->message) != noErr ) { Point where; SetPt(&where, 70, 50); ShowCursor(); (void) DIBadMount(where, pEvent->message); } break; case mouseUp: break; case mouseDown: { short part = FindWindow(pEvent->where, &pWindow); DoAdjustCursor(pWindow, &pEvent->where); switch ( part ) { case inContent: if (pWindow != FrontWindow()) SelectWindow(pWindow); else DoContentClick(pWindow); break; case inGoAway: if (TrackGoAway(pWindow, pEvent->where) ) { // // added option-close, because it’s in the HIG // if( pEvent->modifiers & optionKey ) { (void) CloseAllWindows( false ); } else { DoCommand(pWindow, cClose, 0, 0); } } break; case inGrow: DoGrowWindow(pWindow, pEvent); break; case inZoomIn: case inZoomOut: if ( TrackBox(pWindow, pEvent->where, part) ) DoZoomWindow(pWindow, part); break; case inProxyIcon: // // We’ve seen a hit in the window proxy, so drag the window proxy // // We should only be here on a machine with the native window manager // but we still want to conditionalize it to be fully paraniod // // check(gMachineInfo.haveProxyIcons); { WindowDataPtr pData = GetWindowInfo(pWindow); if( gMachineInfo.haveProxyIcons && (pData != NULL) ) { OSStatus status = TrackWindowProxyDrag( pWindow, pEvent->where ); if( status == errUserWantsToDragWindow ) handled = false; else if( status == noErr ) handled = true; } } // fall through case inDrag: if( !handled ) { WindowDataPtr pData = GetWindowInfo(pWindow); // // Show the file path select popup // if( gMachineInfo.haveProxyIcons && (pData != NULL) ) { if( IsWindowPathSelectClick( pWindow, pEvent ) ) { SInt32 itemSelected; if(WindowPathSelect( pWindow, NULL, &itemSelected ) == noErr ) { // switch to the Finder, since the window probably isn’t visible. if( LoWord(itemSelected) > 1 ) { BringFinderToFront(); } } handled = true; } } if( !handled ) { BitMap screenBits; GetQDGlobalsScreenBits( &screenBits ); #if ALLOW_QUICKTIME if ( (pData) && (pData->dragWindowAligned) ) DragAlignedWindow((WindowPtr) pWindow, pEvent->where, &screenBits.bounds, nil, nil); else DragWindow(pWindow, pEvent->where, &screenBits.bounds); #else DragWindow(pWindow, pEvent->where, &screenBits.bounds); } #endif } break; case inMenuBar: /* process a mouse menu command (if any) */ { long menuResult; WindowDataPtr pData; // force these threads to run to completion so the // contents of the menus are fully initialized if (gFontThread != kNoThreadID) { gDontYield = true; SetThreadState(gFontThread, kReadyThreadState, gFontThread); YieldToThread(gFontThread); gDontYield = false; } pWindow = FrontWindow(); pData = GetWindowInfo(pWindow); if ((pData) && (pData->pPreMenuAccess)) (void) (*(pData->pPreMenuAccess)) (pWindow, pData); AdjustMenus(pWindow, true, false); InitCursor(); menuResult = MenuSelect(pEvent->where); if ( (gMachineInfo.haveTSM) && (TSMMenuSelect(menuResult)) ) HiliteMenu(0); else DoMenuCommand(pWindow, menuResult, 0); } break; case inSysWindow: /* let the system handle the mouseDown */ SystemClick(pEvent, pWindow); break; } // switch(part) } break; case keyDown: case autoKey: /* check for menukey equivalents */ DoKeyEvent(pWindow, pEvent, true); break; case updateEvt: pWindow = (WindowPtr) pEvent->message; DoUpdateWindow(pWindow); break; } // switch (pEvent->what) } // HandleEvent // ----------------------------------------------------------------------------------------------------------- #pragma segment Main static void SynchronizeFiles( void ) { // // File synchronization for all document windows // static UInt32 nextSynchTicks = 10; UInt32 currentTicks = TickCount(); WindowPtr currentWindow = FrontWindow(); // only synchronize every so often... if( currentTicks > nextSynchTicks ) { // // Loop over all our document windows, // searching for files whose locations have changed // while ( currentWindow != NULL ) { WindowDataPtr documentWindowData = GetWindowInfo(currentWindow); // // If it's a SimpleText-owned window and it has an associated file... // if( (documentWindowData != NULL) && (documentWindowData->dataRefNum != -1) ) { Boolean wasChanged = false; FSSpec newSpec; FolderType folder = 0; // // Ask the Alias Manager where the window went // (void) ResolveAlias( NULL, documentWindowData->fileAlias, &newSpec, &wasChanged ); if( wasChanged ) { // // The file location has changed; update the window // documentWindowData->fileSpec = newSpec; // user might have renamed the file SetWTitle( currentWindow, newSpec.name ); // // Close the window if the user moved the Is it in the trash? // IdentifyFolder( newSpec.vRefNum, newSpec.parID, &folder ); if( folder == kTrashFolderType ) { DoCloseWindow( currentWindow, false, 0 ); // false->not quitting } } } currentWindow = GetNextWindow( currentWindow ); } // // To avoid flooding the CPU, wait at least one second // between file synch checks // nextSynchTicks = ( currentTicks + 60 ); } } static OSErr DoEventLoop(void) { OSErr anErr = noErr; Boolean gotEvent; Boolean trueGotEvent; WindowPtr pWindow; do { pWindow = GetWindowList(); // walk all of our windows, even invisible ones /* We used to call DoAdjustCursor every time through the event loop, but that produced nasty cursor flickering when using the magic marker cursor over GX documents. We're now smarter and allow the adjustCursor callback to manipulate the cursor region. However, there may still be cases where the cursor doesn't get adjusted properly. If you suspect a cursor adjustment problem, try putting this call to DoAdjustCursor back in and see what the cursor does. Then fix the code to accurately maintain the cursor region and remove the DoAdjustCursor call. -ecs 11/25/96 */ // DoAdjustCursor(pWindow, nil); gotEvent = WaitNextEvent(everyEvent, &gEvent, DetermineWaitTime(pWindow), gCursorRgn); trueGotEvent = gotEvent; // // Synchronize all files on every event // SynchronizeFiles(); // WNE may close the window if it's owned by some silly extension. pWindow = GetWindowList(); // let text services handle the event first if it wishes to do so if ( gMachineInfo.haveTSM ) { ScriptCode keyboardScript; WindowPtr theFront = FrontWindow(); if (theFront) { CGrafPtr fPort = GetWindowPort(theFront); SetPort((GrafPtr) fPort); keyboardScript = GetScriptManagerVariable(smKeyScript); if (FontToScript(GetPortTextFont(fPort)) != keyboardScript) TextFont(GetScriptVariable(keyboardScript, smScriptAppFond)); } if (TSMEvent(&gEvent)) gotEvent = false; } // let all windows filter this event, and get time if they wish to while (pWindow) { WindowDataPtr pData = GetWindowInfo(pWindow); Boolean finishedEvent = false; // if we hit a window we know about, then do filtering if (pData) { if (pData->pFilterEvent) finishedEvent = (*(pData->pFilterEvent)) (pWindow, pData, &gEvent); } // if filtering indicates complete handling of event, then stop, and // do no regular processing. if (finishedEvent) { gotEvent = false; pWindow = nil; } else pWindow = GetNextWindow(pWindow); } if (gotEvent) HandleEvent(&gEvent); // close request? if (gAllDone) { gAllDone = CloseAllWindows( true ); } // our threads are low-priority, so we only give time to them on idle if (gMachineInfo.haveThreads && !trueGotEvent && !gAllDone) YieldToAnyThread(); } while (!gAllDone); return anErr; } // DoEventLoop // // Close all windows // // Returns false to cancel // static Boolean CloseAllWindows( Boolean quitting ) { WindowPtr pWindow, nextWindow; OSStatus closeError; Boolean notCanceled = true; pWindow = FrontWindow(); while ( (pWindow != NULL) && notCanceled ) { nextWindow = GetNextWindow(pWindow); closeError = DoCloseWindow(pWindow, quitting, false); // ••• why not just require the window to always return an error if it doesn’t close? // window didn't close? then don't quit if (pWindow == FrontWindow()) notCanceled = false; // something bad happened, then don't quit if ( closeError != noErr ) notCanceled = false; pWindow = nextWindow; } return notCanceled; } // -------------------------------------------------------------------------------------------------------------- // DRAG MANAGEMENT GLOBAL SUPPORT ROUTINES // -------------------------------------------------------------------------------------------------------------- // Globals for our drag handlers Boolean gCanAccept; // if we can receive the item(s) being dragged // -------------------------------------------------------------------------------------------------------------- #pragma segment Drag static pascal OSErr GlobalTrackingHandler(short message, WindowPtr pWindow, void *handlerRefCon, DragReference theDragRef) { #pragma unused(handlerRefCon) WindowDataPtr pData = GetWindowInfo(pWindow); // Call the tracking handler associated with this type of window. Only allow messages referencing // a specific window to be passed to the handler. if (pData) { if (pData->pDragTracking) return ((*(pData->pDragTracking)) (pWindow, pData, theDragRef, message)); } return noErr; } // GlobalTrackingHandler DragTrackingHandlerUPP gGlobalTrackingHandler; // -------------------------------------------------------------------------------------------------------------- #pragma segment Drag static pascal OSErr GlobalReceiveHandler(WindowPtr pWindow, void *handlerRefCon, DragReference theDragRef) { #pragma unused(handlerRefCon) WindowDataPtr pData = GetWindowInfo(pWindow); if (pData) { if (pData->pDragTracking) return ((*(pData->pDragReceive)) (pWindow, pData, theDragRef)); } return noErr; } // GlobalReceiveHandler DragReceiveHandlerUPP gGlobalReceiveHandler; // -------------------------------------------------------------------------------------------------------------- // // IsOnlyThisFlavor - Given a DragReference and a FlavorType, we iterate through the drag items to determine if // all are of flavor theType. If this is so, we return true. If any of the items are not // theType, we return false, indicating that we should not accept the drag. // #pragma segment Drag Boolean IsOnlyThisFlavor(DragReference theDragRef, FlavorType theType) { unsigned short items, index; FlavorFlags theFlags; ItemReference itemID; OSErr anErr = noErr; CountDragItems(theDragRef, &items); for(index = 1; index <= items; index++) { GetDragItemReferenceNumber(theDragRef, index, &itemID); anErr = GetFlavorFlags(theDragRef, itemID, theType, &theFlags); if(anErr == noErr) continue; // it's okay, this flavor is cool return false; // this item has at least one flavor we don't like } return true; // all flavors in this item were cool } // IsOnlyThisFlavor // -------------------------------------------------------------------------------------------------------------- // // IsDropInFinderTrash - Returns true if the given dropLocation AEDesc is a descriptor of the Finder's Trash. // #pragma segment Drag Boolean IsDropInFinderTrash(AEDesc *dropLocation) { OSErr result; AEDesc dropSpec; FSSpec *theSpec; CInfoPBRec thePB; short trashVRefNum; long trashDirID; // Coerce the dropLocation descriptor into an FSSpec. If there's no dropLocation or // it can't be coerced into an FSSpec, then it couldn't have been the Trash. if ((dropLocation->descriptorType != typeNull) && (AECoerceDesc(dropLocation, typeFSS, &dropSpec) == noErr)) { AEGetDescData(dropLocation, typeFSS, &theSpec, sizeof(FSSpec) ); // Get the directory ID of the given dropLocation object. thePB.dirInfo.ioCompletion = 0L; thePB.dirInfo.ioNamePtr = (StringPtr) &theSpec->name; thePB.dirInfo.ioVRefNum = theSpec->vRefNum; thePB.dirInfo.ioFDirIndex = 0; thePB.dirInfo.ioDrDirID = theSpec->parID; result = PBGetCatInfoSync(&thePB); AEDisposeDesc(&dropSpec); if (result != noErr) return false; // If the result is not a directory, it must not be the Trash. if (!(thePB.dirInfo.ioFlAttrib & (1 << 4))) return false; // Get information about the Trash folder. FindFolder(theSpec->vRefNum, kTrashFolderType, kCreateFolder, &trashVRefNum, &trashDirID); // If the directory ID of the dropLocation object is the same as the directory ID // returned by FindFolder, then the drop must have occurred into the Trash. if (thePB.dirInfo.ioDrDirID == trashDirID) return true; } return false; } // IsDropInFinderTrash // -------------------------------------------------------------------------------------------------------------- // APPLE EVENT SUPPORT ROUTINES // -------------------------------------------------------------------------------------------------------------- #pragma segment Main static OSErr MissingParameterCheck( const AppleEvent *inputEvent) /* This routine checks an input AppleEvent for the missing keyword. If the missing keyword is found, that means that some required parameters were missing (ie, an error). However, if the missing keyword isn't found, that means that we aren't missing any required parameters (that is to say, all REQUIRED parameters were supplied by the person who created the event). SOME DAY, THE ABOVE COMMENT WILL MAKE SENSE TO YOU. IT STILL DOESN'T TO ME AND I WAS THE ONE WHO WROTE IT. */ { OSErr anErr; AEKeyword missingKeyword; DescType ignoredActualType; Size ignoredActualSize; anErr = AEGetAttributePtr( inputEvent, keyMissedKeywordAttr, typeWildCard, &ignoredActualType, (Ptr) &missingKeyword, sizeof(AEKeyword), &ignoredActualSize); if (anErr == noErr) anErr = errAEParamMissed; else if (anErr == errAEDescNotFound) anErr = noErr; return anErr; } // MissingParameterCheck // -------------------------------------------------------------------------------------------------------------- #pragma segment Main static pascal OSErr DoOpenApp( const AppleEvent *inputEvent, AppleEvent *outputEvent, UInt32 handlerRefCon) { #pragma unused (outputEvent, handlerRefCon) DoCommand(nil, cNew, 0, 0); // so that the initial document opens more quickly, we don't start // the threads until we get an OpenApp or OpenDocument AppleEvent if (gStarterThread != kNoThreadID) SetThreadState(gStarterThread, kReadyThreadState, gStarterThread); return(MissingParameterCheck(inputEvent)); } // DoOpenApp // -------------------------------------------------------------------------------------------------------------- #pragma segment Main static pascal OSErr DoReopenApp( const AppleEvent *inputEvent, AppleEvent *outputEvent, UInt32 handlerRefCon) { #pragma unused (outputEvent, handlerRefCon) if (FrontWindow() == nil) DoCommand(nil, cNew, 0, 0); return(MissingParameterCheck(inputEvent)); } // DoReopenApp // -------------------------------------------------------------------------------------------------------------- #pragma segment Main static pascal OSErr DoQuitApp( const AppleEvent *inputEvent, AppleEvent *outputEvent, UInt32 handlerRefCon) { #pragma unused (outputEvent, handlerRefCon) DoCommand(nil, cQuit, 0, 0); return(MissingParameterCheck(inputEvent)); } // DoQuitApp #if 0 // AEC, it does not appear this is ever called. Do we need it? WindowPtr OpenDoc(short DocKind, FSSpec *spec, StringPtr pass) { OSErr anErr; Boolean wasAlreadyOpen; FInfo theFileInfo; anErr = FSpGetFInfo(spec, &theFileInfo); if (anErr == noErr) anErr = DetermineWindowTypeOrOpen(spec, theFileInfo.fdType, nil, nil, &wasAlreadyOpen); return(NULL); // sorry, we won't tell you if it was successful } #endif // AEC // -------------------------------------------------------------------------------------------------------------- #pragma segment Main // AEC, changed prototype to match headers static pascal OSErr DoOpenOrPrint( const AppleEvent *inputEvent, StringPtr pPrinterName) // nil == 0, zero length == print to default, other == printer name { OSErr anErr, anErr2; AEDescList docList; // list of docs passed in long index, itemsInList; void* hPrint = 0; Boolean wasAlreadyOpen; anErr = AEGetParamDesc( inputEvent, keyDirectObject, typeAEList, &docList); nrequire(anErr, GetFileList); anErr = AECountItems( &docList, &itemsInList); // how many files passed in nrequire(anErr, CountDocs); for (index = 1; index <= itemsInList; index++) // handle each file passed in { AEKeyword keywd; DescType returnedType; Size actualSize; FSSpec theFSS; anErr = AEGetNthPtr( &docList, index, typeFSS, &keywd, &returnedType, // get file's info (Ptr)(&theFSS), sizeof(theFSS), &actualSize); nrequire(anErr, AEGetNthPtr); { FInfo theFileInfo; anErr = FSpGetFInfo(&theFSS, &theFileInfo); if (anErr == noErr) anErr = DetermineWindowTypeOrOpen(&theFSS, theFileInfo.fdType, nil, nil, &wasAlreadyOpen); if (anErr == eDocumentWrongKind) { if (pPrinterName) ConductErrorDialog(anErr, cPrint, cancel); else ConductErrorDialog(anErr, cOpen, cancel); anErr = noErr; break; } nrequire(anErr, DetermineWindowTypeOrOpen); } if (pPrinterName) { WindowPtr pWindow = FrontWindow(); WindowDataPtr pData = GetWindowInfo(pWindow); if (pData->pPrintPage) { if (index == 1) { anErr = DoPrintSetup(pWindow, pPrinterName); if (anErr == noErr) anErr = DoPrint(pWindow, pData->hPageFormat, pData->hPrintSettings, false); } } if (!wasAlreadyOpen) DoCloseWindow(pWindow, false, 0); if (anErr != noErr) break; } } // finally, make sure we didn't miss any parameters anErr2 = MissingParameterCheck(inputEvent); if (anErr == noErr) anErr = anErr2; // FALL THROUGH EXCEPTION HANDLING DetermineWindowTypeOrOpen: AEGetNthPtr: CountDocs: // done with doc list (void) AEDisposeDesc( &docList); GetFileList: // don't report cancels from prints if (pPrinterName) { if (anErr == kPMCancel) anErr = noErr; } if ( (anErr != noErr) && (anErr != eActionAlreadyHandled) && (anErr != eUserCanceled) ) { if (pPrinterName) ConductErrorDialog(anErr, cPrint, cancel); else ConductErrorDialog(anErr, cOpen, cancel); } return anErr; } // DoOpenOrPrint // -------------------------------------------------------------------------------------------------------------- #pragma segment Main static pascal OSErr DoOpenDocument( const AppleEvent *inputEvent, AppleEvent *outputEvent, UInt32 handlerRefCon) { #pragma unused (outputEvent, handlerRefCon) OSErr anErr; if (IsCommandEnabled(cOpen)) { anErr = DoOpenOrPrint(inputEvent, nil); } else { anErr = errAEEventNotHandled; ConductErrorDialog(anErr, cOpen, cancel); } // so that the initial document opens more quickly, we don't start // the threads until we get an OpenApp or OpenDocument AppleEvent if (gStarterThread != kNoThreadID) SetThreadState(gStarterThread, kReadyThreadState, gStarterThread); return anErr; } // DoOpenDocument // -------------------------------------------------------------------------------------------------------------- #pragma segment Main static pascal OSErr DoPrintDocument( const AppleEvent *inputEvent, AppleEvent *outputEvent, UInt32 handlerRefCon) { #pragma unused (outputEvent, handlerRefCon) OSErr anErr; FSSpec printerFSS; AEDescList dtpList; // list of docs passed in if (IsCommandEnabled(cOpen)) { // try to find out if this doc was dropped onto a printer anErr = AEGetAttributeDesc( inputEvent, keyOptionalKeywordAttr, typeAEList, &dtpList); if (anErr == noErr) // doc dragged to dtp? { AEKeyword keywd; DescType returnedType; Size actualSize; anErr = AEGetNthPtr( &dtpList, 1, typeFSS, &keywd, &returnedType, // get dtp info (Ptr)(&printerFSS), sizeof(printerFSS), &actualSize); } // if it wasn't, that's not an error, just print normally if (anErr != noErr) { printerFSS.name[0] = 0; anErr = noErr; } anErr = DoOpenOrPrint(inputEvent, &printerFSS.name[0]); } else { anErr = errAEEventNotHandled; ConductErrorDialog(anErr, cPrint, cancel); } return anErr; } // DoPrintDocument // -------------------------------------------------------------------------------------------------------------- #pragma segment Main // -------------------------------------------------------------------------------------------------------------- // MAIN INITIALIZE/SHUTDOWN/LOOP ROUTINES // -------------------------------------------------------------------------------------------------------------- #pragma segment Main // -------------------------------------------------------------------------------------------------------------- #pragma segment Initialize // -------------------------------------------------------------------------------------------------------------- // must be in Main because it runs in a thread and we don't want the segment unloaded // while some other thread is running #pragma segment Main // -------------------------------------------------------------------------------------------------------------- // must be in Main because it runs in a thread and we don't want the segment unloaded // while some other thread is running #pragma segment Main #if 0 static long SortAndAddMenu(MenuHandle menu, Str255 newItem) { short numInMenu = CountMItems(menu); short i; Str255 oldItem; for (i = 1; i <= numInMenu; ++i) { GetMenuItemText(menu, i, oldItem); switch(IUCompString(newItem, oldItem)) { // already in? Return index case 0: return(i); break; // less than, keep scanning case 1: break; // greater than, add back one case -1: InsertMenuItem(menu, "\pTom Dowdy", i-1); SetMenuItemText(menu, i, newItem); return(i); break; } } // fall off the end? add at the end InsertMenuItem(menu, "\pTom Dowdy", numInMenu); SetMenuItemText(menu, numInMenu+1, newItem); return(numInMenu+1); } // SortAndAddMenu #endif // must be in Main because it runs in a thread and we don't want the segment unloaded // while some other thread is running #pragma segment Initialize static OSErr BuildFontMenu(MenuHandle menu) { OSErr anErr = noErr; AppendResMenu(menu, 'FONT'); return(anErr); } // BuildFontMenu // -------------------------------------------------------------------------------------------------------------- // structures for FastGetNewMBar typedef struct { MenuHandle menuOH; short menuLeft; } MenuRec; typedef struct { short lastMenu; short lastRight; short mbResID; MenuRec menu[1]; } DynamicMenuList; // -------------------------------------------------------------------------------------------------------------- #pragma segment Initialize /* A much faster implementation of GetNewMBar, cuts about 0.3 second off the boot time on a 7500/100 running 7.5.5. DISABLED THIS CODE, APPLEGUIDE DEPENDS UPON INSERTMENU, WHICH THIS DOESN'T CALL. STILL, THIS WOULD BE NICE TO DO AT SOME TIME! */ #if 0 static Handle FastGetNewMBar(short id) { Handle hMbar; short cMenus; int iMenu; MenuHandle hmenu; DynamicMenuList** hmenulist; hMbar = GetResource('MBAR', id); require(hMbar != NULL, GetResource); cMenus = *(short*) *hMbar; hmenulist = (DynamicMenuList**) NewHandleClear(sizeof(DynamicMenuList) + sizeof(MenuRec) * cMenus); require(hmenulist != NULL, NewMenuList); for (iMenu = 0; iMenu < cMenus; iMenu++) { hmenu = GetMenu(*(short*) ((BytePtr) *hMbar + 2 + 2 * iMenu)); if (hmenu != NULL) (*hmenulist)->menu[iMenu].menuOH = hmenu; } ReleaseResource(hMbar); (*hmenulist)->lastMenu = cMenus * 6; return (Handle) hmenulist; // EXCEPTION HANDLING NewMenuList: ReleaseResource(hMbar); GetResource: return NULL; } // FastGetNewMBar #endif // -------------------------------------------------------------------------------------------------------------- #pragma segment Initialize static OSErr DoInitialize(void) { // short count; // loop counter Handle menuBar; // for loading our menus in OSErr anErr = noErr; // any errors we get, none so far long version; // version for Gestalt calls gMachineInfo.haveAppearanceMgr = (Gestalt(gestaltAppearanceAttr, &version) == noErr) && ((version & (1<<gestaltAppearanceExists)) != 0); if (gMachineInfo.haveAppearanceMgr) RegisterAppearanceClient(); #if 0 InitGraf((Ptr) &FrontWindow()); InitFonts(); InitWindows(); InitMenus(); TEInit(); InitDialogs(nil); InitCursor(); #endif InitCursor(); //InitializeQTML( 0 ); gAllDone = false; gMachineInfo.lastBalloonIndex = iNoBalloon; gMachineInfo.amInBackground = false; gMachineInfo.documentCount = 1; #if ALLOW_QUICKTIME gMachineInfo.haveQuickTime = (Gestalt(gestaltQuickTime, &version) == noErr); #else gMachineInfo.haveQuickTime = false; #endif gMachineInfo.haveRecording = (Gestalt(gestaltSoundAttr, &version) == noErr) && ((version & (1<<gestaltHasSoundInputDevice)) != 0); gMachineInfo.haveTTS = (Gestalt(gestaltSpeechAttr, &version) == noErr) && ((version & (1<<gestaltSpeechMgrPresent)) != 0); gMachineInfo.haveTSM = (Gestalt(gestaltTSMgrVersion, &version) == noErr) && (version >= 1); gMachineInfo.haveTSMTE = (Gestalt(gestaltTSMTEAttr, &version) == noErr) && ((version & (1<<gestaltTSMTE)) != 0); gMachineInfo.haveDragMgr = (Gestalt(gestaltDragMgrAttr, &version) == noErr) && ((version & (1<<gestaltDragMgrPresent)) != 0) && (Gestalt(gestaltTEAttr, &version) == noErr) && ((version & (1<<gestaltTEHasGetHiliteRgn)) != 0); gMachineInfo.haveThreeD = false; gMachineInfo.haveAppleGuide = (Gestalt(gestaltHelpMgrAttr, &version) == noErr) && ((version & (1<<gestaltAppleGuidePresent)) != 0); gMachineInfo.haveThreads = (Gestalt(gestaltThreadMgrAttr, &version) == noErr) && ((version & (1<<gestaltThreadMgrPresent)) != 0); gMachineInfo.haveNavigationServices = NavServicesAvailable(); // // Record the presence of >= 8.5 window manager features. // gMachineInfo.haveProxyIcons = false; gMachineInfo.haveFloatingWindows = false; #if TARGET_CPU_PPC // if( ( Gestalt( gestaltWindowMgrAttr, &version ) == noErr ) ) { if( version & (1L << gestaltWindowMgrPresentBit) ) { gMachineInfo.haveProxyIcons = true; if( version & (1L << gestaltHasFloatingWindows) ) gMachineInfo.haveFloatingWindows = true; } } #endif // initialize text services if they exist if (gMachineInfo.haveTSMTE) { if (InitTSMAwareApplication() != noErr) { gMachineInfo.haveTSM = false; gMachineInfo.haveTSMTE = false; } } // save away info we need from the get-go gApplicationResFile = CurResFile(); gCursorRgn = NewRgn(); // load up the menus menuBar = (Handle) GetNewMBar(rMenuBar); /* read menus into menu bar */ anErr = ResError(); if ( (anErr == noErr) && (menuBar == nil) ) anErr = resNotFound; nrequire(anErr, GetNewMBar); // install menus SetMenuBar(menuBar); DisposeHandle(menuBar); // Build the font menu anErr = BuildFontMenu(GetMenuHandle(mFont)); nrequire(anErr, BuildFontMenu); // insert our heirarchical menus { MenuHandle menu = MacGetMenu( mVoices ); short menuID, itemID; InsertMenu( menu, hierMenu ); CommandToIDs(cSelectVoice, &menuID, &itemID); menu = GetMenuHandle(menuID); SetItemCmd( menu, itemID, hMenuCmd ); SetItemMark( menu, itemID, mVoices ); } if (!AdjustMenus(nil, true, false)) DrawMenuBar(); // start up QuickTime, but problems result in us pretending not to have it #if ALLOW_QUICKTIME if (gMachineInfo.haveQuickTime) if (EnterMovies() != noErr) gMachineInfo.haveQuickTime = false; #endif // Install AppleEvent handlers for the base classes #define INSTALL(event, handler) \ AEInstallEventHandler(kCoreEventClass, event, handler, 0, false) // AEC, changed to use the correct handler procs INSTALL (kAEOpenApplication, NewAEEventHandlerProc(DoOpenApp)); INSTALL ('rapp', NewAEEventHandlerProc(DoReopenApp)); INSTALL (kAEQuitApplication, NewAEEventHandlerProc(DoQuitApp)); INSTALL (kAEOpenDocuments, NewAEEventHandlerProc(DoOpenDocument)); INSTALL (kAEPrintDocuments, NewAEEventHandlerProc(DoPrintDocument)); #undef INSTALL // AEC, added control procs gVActionProc = NewControlActionProc(VActionProc); gHActionProc = NewControlActionProc(HActionProc); // Install our global dragging procs, but only if we have Drag and Drop. An error results // in us pretending that we don't have drag support. Notice that in the test above, we also // require TextEdit to have TEGetHiliteRgn avalilable, which is always the case with the // present Drag Manager. if (gMachineInfo.haveDragMgr) { gGlobalTrackingHandler = NewDragTrackingHandlerProc(GlobalTrackingHandler); gGlobalReceiveHandler = NewDragReceiveHandlerProc(GlobalReceiveHandler); anErr = InstallTrackingHandler(gGlobalTrackingHandler, nil, nil); if (anErr == noErr) { anErr = InstallReceiveHandler(gGlobalReceiveHandler, nil, nil); if (anErr != noErr) { RemoveTrackingHandler(gGlobalTrackingHandler, nil); gMachineInfo.haveDragMgr = false; } } else gMachineInfo.haveDragMgr = false; } // for AppleScript anErr = OpenADefaultComponent(kOSAComponentType, kOSAGenericScriptingComponentSubtype, &gOSAComponent); return noErr; // EXCEPTION HANDLING BuildFontMenu: GetNewMBar: // SysEnvirons: ConductErrorDialog(anErr, cNull, cancel); return anErr; } // DoInitialize // -------------------------------------------------------------------------------------------------------------- #pragma segment Terminate static OSErr DoTerminate(void) { OSErr anErr = noErr; if (gFontThread != kNoThreadID) DisposeThread(gFontThread, &gThreadResults, false); if (gStarterThread != kNoThreadID) DisposeThread(gStarterThread, &gThreadResults, false); #if ALLOW_QUICKTIME if (gMachineInfo.haveQuickTime) ExitMovies(); #endif if (gMachineInfo.haveTSMTE) CloseTSMAwareApplication(); if (gMachineInfo.haveDragMgr) { RemoveReceiveHandler(gGlobalReceiveHandler, nil); RemoveTrackingHandler(gGlobalTrackingHandler, nil); } if (gMachineInfo.haveAppearanceMgr) UnregisterAppearanceClient(); // for AppleScript if (gOSAComponent) CloseComponent(gOSAComponent); return anErr; } // DoTerminate // -------------------------------------------------------------------------------------------------------------- #pragma segment Main int main(int argc, char *argv[]) { #pragma unused (argc, argv) OSErr anErr; #ifndef __MWERKS__ UnloadSeg((Ptr) _DataInit); /* note that _DataInit must not be in Main! */ #endif //Not for Carbon anymore! // MaxApplZone(); /* expand the heap so code segments load at the top */ // MoreMasters(); MoreMasters(); MoreMasters(); /* we love handles */ #ifdef __MWERKS__ #if __option(profile) ProfilerInit(collectSummary, bestTimeBase, 500, 10); #endif #endif anErr = DoInitialize(); #ifdef __MWERKS__ #if __option(profile) ProfilerDump("\pboot.prof"); ProfilerSetStatus(false); ProfilerClear(); #endif #endif UnloadSeg((Ptr) DoInitialize); if (anErr == noErr) { DoEventLoop(); #ifdef __MWERKS__ #if __option(profile) ProfilerTerm(); #endif #endif // REVIEW: don't want to unload the segment we're in!! // UnloadSeg((Ptr) DoEventLoop); DoTerminate(); } return 0; } // main